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#pragma message (OPENSSL_VERSION_TEXT)
27#endif
28
29using Poco::RandomInputStream;
30using Poco::Thread;
31
32
33namespace Poco {
34namespace Crypto {
35
36Poco::FastMutex OpenSSLInitializer::_mutex;
37Poco::FastMutex* OpenSSLInitializer::_mutexes(0);
38int OpenSSLInitializer::_rc(0);
39bool OpenSSLInitializer::_disableSSLInitialization = false;
40
41OpenSSLInitializer::OpenSSLInitializer()
42{
43 initialize();
44}
45
46
47OpenSSLInitializer::~OpenSSLInitializer()
48{
49 try
50 {
51 uninitialize();
52 }
53 catch (...)
54 {
55 poco_unexpected();
56 }
57}
58
59
60void OpenSSLInitializer::initialize()
61{
62 FastMutex::ScopedLock lock(_mutex);
63 if (++_rc == 1)
64 {
65#if OPENSSL_VERSION_NUMBER >= 0x0907000L
66 OPENSSL_config(NULL);
67#endif
68 if(! _disableSSLInitialization)
69 {
70 SSL_library_init();
71 SSL_load_error_strings();
72 OpenSSL_add_all_algorithms();
73 }
74
75 char seed[SEEDSIZE];
76 RandomInputStream rnd;
77 rnd.read(seed, sizeof(seed));
78 RAND_seed(seed, SEEDSIZE);
79
80 if(CRYPTO_get_locking_callback() == NULL)
81 {
82 int nMutexes = CRYPTO_num_locks();
83 _mutexes = new Poco::FastMutex[nMutexes];
84 CRYPTO_set_locking_callback(&OpenSSLInitializer::lock);
85#ifndef POCO_OS_FAMILY_WINDOWS
86// Not needed on Windows (see SF #110: random unhandled exceptions when linking with ssl).
87// https://sourceforge.net/p/poco/bugs/110/
88//
89// From http://www.openssl.org/docs/crypto/threads.html :
90// "If the application does not register such a callback using CRYPTO_THREADID_set_callback(),
91// then a default implementation is used - on Windows and BeOS this uses the system's
92// default thread identifying APIs"
93#ifndef OPENSSL_NO_DEPRECATED
94 CRYPTO_set_id_callback(&OpenSSLInitializer::id);
95#else
96 CRYPTO_THREADID tid;
97 CRYPTO_THREADID_set_numeric(&tid, OpenSSLInitializer::id());
98#endif /* OPENSSL_NO_DEPRECATED */
99#endif
100 CRYPTO_set_dynlock_create_callback(&OpenSSLInitializer::dynlockCreate);
101 CRYPTO_set_dynlock_lock_callback(&OpenSSLInitializer::dynlock);
102 CRYPTO_set_dynlock_destroy_callback(&OpenSSLInitializer::dynlockDestroy);
103 }
104 }
105}
106
107
108void OpenSSLInitializer::uninitialize()
109{
110 FastMutex::ScopedLock lock(_mutex);
111 if (--_rc == 0)
112 {
113 if(_mutexes != NULL)
114 {
115 CRYPTO_set_dynlock_create_callback(0);
116 CRYPTO_set_dynlock_lock_callback(0);
117 CRYPTO_set_dynlock_destroy_callback(0);
118 CRYPTO_set_locking_callback(0);
119#ifndef POCO_OS_FAMILY_WINDOWS
120#ifndef OPENSSL_NO_DEPRECATED
121 CRYPTO_set_id_callback(0);
122#else
123 CRYPTO_THREADID tid;
124 CRYPTO_THREADID_set_numeric(&tid, 0);
125#endif /* OPENSSL_NO_DEPRECATED */
126#endif
127 delete [] _mutexes;
128 }
129
130 if(! _disableSSLInitialization)
131 {
132 EVP_cleanup();
133 ERR_free_strings();
134 CONF_modules_free();
135 }
136 }
137}
138
139
140void OpenSSLInitializer::lock(int mode, int n, const char* file, int line)
141{
142 if (mode & CRYPTO_LOCK)
143 _mutexes[n].lock();
144 else
145 _mutexes[n].unlock();
146}
147
148
149#ifndef POCO_OS_FAMILY_WINDOWS
150
151unsigned long OpenSSLInitializer::id()
152{
153 // Note: we use an old-style C cast here because
154 // neither static_cast<> nor reinterpret_cast<>
155 // work uniformly across all platforms.
156 return (unsigned long) Poco::Thread::currentTid();
157}
158
159#endif
160
161
162struct CRYPTO_dynlock_value* OpenSSLInitializer::dynlockCreate(const char* file, int line)
163{
164 return new CRYPTO_dynlock_value;
165}
166
167
168void OpenSSLInitializer::dynlock(int mode, struct CRYPTO_dynlock_value* lock, const char* file, int line)
169{
170 poco_check_ptr (lock);
171
172 if (mode & CRYPTO_LOCK)
173 lock->_mutex.lock();
174 else
175 lock->_mutex.unlock();
176}
177
178
179void OpenSSLInitializer::dynlockDestroy(struct CRYPTO_dynlock_value* lock, const char* file, int line)
180{
181 delete lock;
182}
183
184
185void initializeCrypto()
186{
187 OpenSSLInitializer::initialize();
188}
189
190
191void uninitializeCrypto()
192{
193 OpenSSLInitializer::uninitialize();
194}
195
196
197} } // namespace Poco::Crypto
198
199// needed for OpenSSL static link
200#if defined(_WIN32) && !defined(POCO_DLL) && (POCO_MSVS_VERSION >= 2015) && !defined(POCO_EXTERNAL_OPENSSL)
201 FILE * __cdecl __iob_func(void)
202 {
203 static FILE poco_iob[] = { stdin, stdout, stderr };
204 return poco_iob;
205 }
206#endif
207