1 //
2 // SSLManager.cpp
3 //
4 // Library: NetSSL_OpenSSL
5 // Package: SSLCore
6 // Module:  SSLManager
7 //
8 // Copyright (c) 2006-2010, Applied Informatics Software Engineering GmbH.
9 // and Contributors.
10 //
11 // SPDX-License-Identifier:	BSL-1.0
12 //
13 
14 
15 #include "Poco/Net/SSLManager.h"
16 #include "Poco/Net/Context.h"
17 #include "Poco/Net/Utility.h"
18 #include "Poco/Net/PrivateKeyPassphraseHandler.h"
19 #include "Poco/Net/RejectCertificateHandler.h"
20 #include "Poco/Crypto/OpenSSLInitializer.h"
21 #include "Poco/Net/SSLException.h"
22 #include "Poco/SingletonHolder.h"
23 #include "Poco/Delegate.h"
24 #include "Poco/StringTokenizer.h"
25 #include "Poco/Util/Application.h"
26 #include "Poco/Util/OptionException.h"
27 
28 
29 namespace Poco {
30 namespace Net {
31 
32 
33 const std::string SSLManager::CFG_PRIV_KEY_FILE("privateKeyFile");
34 const std::string SSLManager::CFG_CERTIFICATE_FILE("certificateFile");
35 const std::string SSLManager::CFG_CA_LOCATION("caConfig");
36 const std::string SSLManager::CFG_VER_MODE("verificationMode");
37 const Context::VerificationMode SSLManager::VAL_VER_MODE(Context::VERIFY_RELAXED);
38 const std::string SSLManager::CFG_VER_DEPTH("verificationDepth");
39 const int         SSLManager::VAL_VER_DEPTH(9);
40 const std::string SSLManager::CFG_ENABLE_DEFAULT_CA("loadDefaultCAFile");
41 const bool        SSLManager::VAL_ENABLE_DEFAULT_CA(true);
42 const std::string SSLManager::CFG_CIPHER_LIST("cipherList");
43 const std::string SSLManager::CFG_CYPHER_LIST("cypherList");
44 const std::string SSLManager::VAL_CIPHER_LIST("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
45 const std::string SSLManager::CFG_PREFER_SERVER_CIPHERS("preferServerCiphers");
46 const std::string SSLManager::CFG_DELEGATE_HANDLER("privateKeyPassphraseHandler.name");
47 const std::string SSLManager::VAL_DELEGATE_HANDLER("KeyConsoleHandler");
48 const std::string SSLManager::CFG_CERTIFICATE_HANDLER("invalidCertificateHandler.name");
49 const std::string SSLManager::VAL_CERTIFICATE_HANDLER("ConsoleCertificateHandler");
50 const std::string SSLManager::CFG_SERVER_PREFIX("openSSL.server.");
51 const std::string SSLManager::CFG_CLIENT_PREFIX("openSSL.client.");
52 const std::string SSLManager::CFG_CACHE_SESSIONS("cacheSessions");
53 const std::string SSLManager::CFG_SESSION_ID_CONTEXT("sessionIdContext");
54 const std::string SSLManager::CFG_SESSION_CACHE_SIZE("sessionCacheSize");
55 const std::string SSLManager::CFG_SESSION_TIMEOUT("sessionTimeout");
56 const std::string SSLManager::CFG_EXTENDED_VERIFICATION("extendedVerification");
57 const std::string SSLManager::CFG_REQUIRE_TLSV1("requireTLSv1");
58 const std::string SSLManager::CFG_REQUIRE_TLSV1_1("requireTLSv1_1");
59 const std::string SSLManager::CFG_REQUIRE_TLSV1_2("requireTLSv1_2");
60 const std::string SSLManager::CFG_REQUIRE_TLSV1_3("requireTLSv1_3");
61 const std::string SSLManager::CFG_DISABLE_PROTOCOLS("disableProtocols");
62 const std::string SSLManager::CFG_DH_PARAMS_FILE("dhParamsFile");
63 const std::string SSLManager::CFG_ECDH_CURVE("ecdhCurve");
64 #ifdef OPENSSL_FIPS
65 const std::string SSLManager::CFG_FIPS_MODE("openSSL.fips");
66 const bool        SSLManager::VAL_FIPS_MODE(false);
67 #endif
68 
69 
SSLManager()70 SSLManager::SSLManager()
71 {
72 }
73 
74 
~SSLManager()75 SSLManager::~SSLManager()
76 {
77 	try
78 	{
79 		shutdown();
80 	}
81 	catch (...)
82 	{
83 		poco_unexpected();
84 	}
85 }
86 
87 
shutdown()88 void SSLManager::shutdown()
89 {
90 	PrivateKeyPassphraseRequired.clear();
91 	ClientVerificationError.clear();
92 	ServerVerificationError.clear();
93 	_ptrDefaultServerContext = 0;
94 	_ptrDefaultClientContext = 0;
95 }
96 
97 
98 namespace
99 {
100 	static Poco::SingletonHolder<SSLManager> singleton;
101 }
102 
103 
instance()104 SSLManager& SSLManager::instance()
105 {
106 	return *singleton.get();
107 }
108 
109 
initializeServer(PrivateKeyPassphraseHandlerPtr ptrPassphraseHandler,InvalidCertificateHandlerPtr ptrHandler,Context::Ptr ptrContext)110 void SSLManager::initializeServer(PrivateKeyPassphraseHandlerPtr ptrPassphraseHandler, InvalidCertificateHandlerPtr ptrHandler, Context::Ptr ptrContext)
111 {
112 	_ptrServerPassphraseHandler  = ptrPassphraseHandler;
113 	_ptrServerCertificateHandler = ptrHandler;
114 	_ptrDefaultServerContext     = ptrContext;
115 }
116 
117 
initializeClient(PrivateKeyPassphraseHandlerPtr ptrPassphraseHandler,InvalidCertificateHandlerPtr ptrHandler,Context::Ptr ptrContext)118 void SSLManager::initializeClient(PrivateKeyPassphraseHandlerPtr ptrPassphraseHandler, InvalidCertificateHandlerPtr ptrHandler, Context::Ptr ptrContext)
119 {
120 	_ptrClientPassphraseHandler  = ptrPassphraseHandler;
121 	_ptrClientCertificateHandler = ptrHandler;
122 	_ptrDefaultClientContext     = ptrContext;
123 }
124 
125 
defaultServerContext()126 Context::Ptr SSLManager::defaultServerContext()
127 {
128 	Poco::FastMutex::ScopedLock lock(_mutex);
129 
130 	if (!_ptrDefaultServerContext)
131 		initDefaultContext(true);
132 
133 	return _ptrDefaultServerContext;
134 }
135 
136 
defaultClientContext()137 Context::Ptr SSLManager::defaultClientContext()
138 {
139 	Poco::FastMutex::ScopedLock lock(_mutex);
140 
141 	if (!_ptrDefaultClientContext)
142 	{
143 		try
144 		{
145 			initDefaultContext(false);
146 		}
147 		catch (Poco::IllegalStateException&)
148 		{
149 			_ptrClientCertificateHandler = new RejectCertificateHandler(false);
150 			_ptrDefaultClientContext = new Context(Context::CLIENT_USE, "", Context::VERIFY_RELAXED, 9, true);
151 			_ptrDefaultClientContext->disableProtocols(Context::PROTO_SSLV2 | Context::PROTO_SSLV3);
152 		}
153 	}
154 
155 	return _ptrDefaultClientContext;
156 }
157 
158 
serverPassphraseHandler()159 SSLManager::PrivateKeyPassphraseHandlerPtr SSLManager::serverPassphraseHandler()
160 {
161 	Poco::FastMutex::ScopedLock lock(_mutex);
162 
163 	if (!_ptrServerPassphraseHandler)
164 		initPassphraseHandler(true);
165 
166 	return _ptrServerPassphraseHandler;
167 }
168 
169 
clientPassphraseHandler()170 SSLManager::PrivateKeyPassphraseHandlerPtr SSLManager::clientPassphraseHandler()
171 {
172 	Poco::FastMutex::ScopedLock lock(_mutex);
173 
174 	if (!_ptrClientPassphraseHandler)
175 		initPassphraseHandler(false);
176 
177 	return _ptrClientPassphraseHandler;
178 }
179 
180 
serverCertificateHandler()181 SSLManager::InvalidCertificateHandlerPtr SSLManager::serverCertificateHandler()
182 {
183 	Poco::FastMutex::ScopedLock lock(_mutex);
184 
185 	if (!_ptrServerCertificateHandler)
186 		initCertificateHandler(true);
187 
188 	return _ptrServerCertificateHandler;
189 }
190 
191 
clientCertificateHandler()192 SSLManager::InvalidCertificateHandlerPtr SSLManager::clientCertificateHandler()
193 {
194 	Poco::FastMutex::ScopedLock lock(_mutex);
195 
196 	if (!_ptrClientCertificateHandler)
197 		initCertificateHandler(false);
198 
199 	return _ptrClientCertificateHandler;
200 }
201 
202 
verifyCallback(bool server,int ok,X509_STORE_CTX * pStore)203 int SSLManager::verifyCallback(bool server, int ok, X509_STORE_CTX* pStore)
204 {
205 	if (!ok)
206 	{
207 		X509* pCert = X509_STORE_CTX_get_current_cert(pStore);
208 		X509Certificate x509(pCert, true);
209 		int depth = X509_STORE_CTX_get_error_depth(pStore);
210 		int err = X509_STORE_CTX_get_error(pStore);
211 		std::string error(X509_verify_cert_error_string(err));
212 		VerificationErrorArgs args(x509, depth, err, error);
213 		if (server)
214 			SSLManager::instance().ServerVerificationError.notify(&SSLManager::instance(), args);
215 		else
216 			SSLManager::instance().ClientVerificationError.notify(&SSLManager::instance(), args);
217 		ok = args.getIgnoreError() ? 1 : 0;
218 	}
219 
220 	return ok;
221 }
222 
223 
privateKeyPassphraseCallback(char * pBuf,int size,int flag,void * userData)224 int SSLManager::privateKeyPassphraseCallback(char* pBuf, int size, int flag, void* userData)
225 {
226 	std::string pwd;
227 	SSLManager::instance().PrivateKeyPassphraseRequired.notify(&SSLManager::instance(), pwd);
228 
229 	strncpy(pBuf, (char *)(pwd.c_str()), size);
230 	pBuf[size - 1] = '\0';
231 	if (size > pwd.length())
232 		size = (int) pwd.length();
233 
234 	return size;
235 }
236 
237 
initDefaultContext(bool server)238 void SSLManager::initDefaultContext(bool server)
239 {
240 	if (server && _ptrDefaultServerContext) return;
241 	if (!server && _ptrDefaultClientContext) return;
242 
243 	Poco::Crypto::OpenSSLInitializer openSSLInitializer;
244 	initEvents(server);
245 	Poco::Util::AbstractConfiguration& config = appConfig();
246 
247 #ifdef OPENSSL_FIPS
248 	bool fipsEnabled = config.getBool(CFG_FIPS_MODE, VAL_FIPS_MODE);
249 	if (fipsEnabled && !Poco::Crypto::OpenSSLInitializer::isFIPSEnabled())
250 	{
251 		Poco::Crypto::OpenSSLInitializer::enableFIPSMode(true);
252 	}
253 #endif
254 
255 	std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX;
256 
257 	Context::Params params;
258 	// mandatory options
259 	params.privateKeyFile = config.getString(prefix + CFG_PRIV_KEY_FILE, "");
260 	params.certificateFile = config.getString(prefix + CFG_CERTIFICATE_FILE, params.privateKeyFile);
261 	params.caLocation = config.getString(prefix + CFG_CA_LOCATION, "");
262 
263 	if (server && params.certificateFile.empty() && params.privateKeyFile.empty())
264 		throw SSLException("Configuration error: no certificate file has been specified");
265 
266 	// optional options for which we have defaults defined
267 	params.verificationMode = VAL_VER_MODE;
268 	if (config.hasProperty(prefix + CFG_VER_MODE))
269 	{
270 		// either: none, relaxed, strict, once
271 		std::string mode = config.getString(prefix + CFG_VER_MODE);
272 		params.verificationMode = Utility::convertVerificationMode(mode);
273 	}
274 
275 	params.verificationDepth = config.getInt(prefix + CFG_VER_DEPTH, VAL_VER_DEPTH);
276 	params.loadDefaultCAs = config.getBool(prefix + CFG_ENABLE_DEFAULT_CA, VAL_ENABLE_DEFAULT_CA);
277 	params.cipherList = config.getString(prefix + CFG_CIPHER_LIST, VAL_CIPHER_LIST);
278 	params.cipherList = config.getString(prefix + CFG_CYPHER_LIST, params.cipherList); // for backwards compatibility
279 	bool requireTLSv1 = config.getBool(prefix + CFG_REQUIRE_TLSV1, false);
280 	bool requireTLSv1_1 = config.getBool(prefix + CFG_REQUIRE_TLSV1_1, false);
281 	bool requireTLSv1_2 = config.getBool(prefix + CFG_REQUIRE_TLSV1_2, false);
282 	bool requireTLSv1_3 = config.getBool(prefix + CFG_REQUIRE_TLSV1_3, false);
283 
284 	params.dhParamsFile = config.getString(prefix + CFG_DH_PARAMS_FILE, "");
285 	params.ecdhCurve    = config.getString(prefix + CFG_ECDH_CURVE, "");
286 
287 	Context::Usage usage;
288 
289 	if (server)
290 	{
291 		if (requireTLSv1_3)
292 			usage = Context::TLSV1_3_SERVER_USE;
293 		else if (requireTLSv1_2)
294 			usage = Context::TLSV1_2_SERVER_USE;
295 		else if (requireTLSv1_1)
296 			usage = Context::TLSV1_1_SERVER_USE;
297 		else if (requireTLSv1)
298 			usage = Context::TLSV1_SERVER_USE;
299 		else
300 			usage = Context::SERVER_USE;
301 		_ptrDefaultServerContext = new Context(usage, params);
302 	}
303 	else
304 	{
305 		if (requireTLSv1_3)
306 			usage = Context::TLSV1_3_CLIENT_USE;
307 		else if (requireTLSv1_2)
308 			usage = Context::TLSV1_2_CLIENT_USE;
309 		else if (requireTLSv1_1)
310 			usage = Context::TLSV1_1_CLIENT_USE;
311 		else if (requireTLSv1)
312 			usage = Context::TLSV1_CLIENT_USE;
313 		else
314 			usage = Context::CLIENT_USE;
315 		_ptrDefaultClientContext = new Context(usage, params);
316 	}
317 
318 	std::string disabledProtocolsList = config.getString(prefix + CFG_DISABLE_PROTOCOLS, "");
319 	Poco::StringTokenizer dpTok(disabledProtocolsList, ";,", Poco::StringTokenizer::TOK_TRIM | Poco::StringTokenizer::TOK_IGNORE_EMPTY);
320 	int disabledProtocols = 0;
321 	for (Poco::StringTokenizer::Iterator it = dpTok.begin(); it != dpTok.end(); ++it)
322 	{
323 		if (*it == "sslv2")
324 			disabledProtocols |= Context::PROTO_SSLV2;
325 		else if (*it == "sslv3")
326 			disabledProtocols |= Context::PROTO_SSLV3;
327 		else if (*it == "tlsv1")
328 			disabledProtocols |= Context::PROTO_TLSV1;
329 		else if (*it == "tlsv1_1")
330 			disabledProtocols |= Context::PROTO_TLSV1_1;
331 		else if (*it == "tlsv1_2")
332 			disabledProtocols |= Context::PROTO_TLSV1_2;
333 		else if (*it == "tlsv1_3")
334 			disabledProtocols |= Context::PROTO_TLSV1_3;
335 	}
336 	if (server)
337 		_ptrDefaultServerContext->disableProtocols(disabledProtocols);
338 	else
339 		_ptrDefaultClientContext->disableProtocols(disabledProtocols);
340 
341 	bool cacheSessions = config.getBool(prefix + CFG_CACHE_SESSIONS, false);
342 	if (server)
343 	{
344 		std::string sessionIdContext = config.getString(prefix + CFG_SESSION_ID_CONTEXT, config.getString("application.name", ""));
345 		_ptrDefaultServerContext->enableSessionCache(cacheSessions, sessionIdContext);
346 		if (config.hasProperty(prefix + CFG_SESSION_CACHE_SIZE))
347 		{
348 			int cacheSize = config.getInt(prefix + CFG_SESSION_CACHE_SIZE);
349 			_ptrDefaultServerContext->setSessionCacheSize(cacheSize);
350 		}
351 		if (config.hasProperty(prefix + CFG_SESSION_TIMEOUT))
352 		{
353 			int timeout = config.getInt(prefix + CFG_SESSION_TIMEOUT);
354 			_ptrDefaultServerContext->setSessionTimeout(timeout);
355 		}
356 	}
357 	else
358 	{
359 		_ptrDefaultClientContext->enableSessionCache(cacheSessions);
360 	}
361 	bool extendedVerification = config.getBool(prefix + CFG_EXTENDED_VERIFICATION, false);
362 	if (server)
363 		_ptrDefaultServerContext->enableExtendedCertificateVerification(extendedVerification);
364 	else
365 		_ptrDefaultClientContext->enableExtendedCertificateVerification(extendedVerification);
366 
367 	bool preferServerCiphers = config.getBool(prefix + CFG_PREFER_SERVER_CIPHERS, false);
368 	if (preferServerCiphers)
369 	{
370 		if (server)
371 			_ptrDefaultServerContext->preferServerCiphers();
372 		else
373 			_ptrDefaultClientContext->preferServerCiphers();
374 	}
375 }
376 
377 
initEvents(bool server)378 void SSLManager::initEvents(bool server)
379 {
380 	initPassphraseHandler(server);
381 	initCertificateHandler(server);
382 }
383 
384 
initPassphraseHandler(bool server)385 void SSLManager::initPassphraseHandler(bool server)
386 {
387 	if (server && _ptrServerPassphraseHandler) return;
388 	if (!server && _ptrClientPassphraseHandler) return;
389 
390 	std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX;
391 	Poco::Util::AbstractConfiguration& config = appConfig();
392 
393 	std::string className(config.getString(prefix + CFG_DELEGATE_HANDLER, VAL_DELEGATE_HANDLER));
394 
395 	const PrivateKeyFactory* pFactory = 0;
396 	if (privateKeyFactoryMgr().hasFactory(className))
397 	{
398 		pFactory = privateKeyFactoryMgr().getFactory(className);
399 	}
400 
401 	if (pFactory)
402 	{
403 		if (server)
404 			_ptrServerPassphraseHandler = pFactory->create(server);
405 		else
406 			_ptrClientPassphraseHandler = pFactory->create(server);
407 	}
408 	else throw Poco::Util::UnknownOptionException(std::string("No passphrase handler known with the name ") + className);
409 }
410 
411 
initCertificateHandler(bool server)412 void SSLManager::initCertificateHandler(bool server)
413 {
414 	if (server && _ptrServerCertificateHandler) return;
415 	if (!server && _ptrClientCertificateHandler) return;
416 
417 	std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX;
418 	Poco::Util::AbstractConfiguration& config = appConfig();
419 
420 	std::string className(config.getString(prefix+CFG_CERTIFICATE_HANDLER, VAL_CERTIFICATE_HANDLER));
421 
422 	const CertificateHandlerFactory* pFactory = 0;
423 	if (certificateHandlerFactoryMgr().hasFactory(className))
424 	{
425 		pFactory = certificateHandlerFactoryMgr().getFactory(className);
426 	}
427 
428 	if (pFactory)
429 	{
430 		if (server)
431 			_ptrServerCertificateHandler = pFactory->create(true);
432 		else
433 			_ptrClientCertificateHandler = pFactory->create(false);
434 	}
435 	else throw Poco::Util::UnknownOptionException(std::string("No InvalidCertificate handler known with the name ") + className);
436 }
437 
438 
appConfig()439 Poco::Util::AbstractConfiguration& SSLManager::appConfig()
440 {
441 	try
442 	{
443 		return Poco::Util::Application::instance().config();
444 	}
445 	catch (Poco::NullPointerException&)
446 	{
447 		throw Poco::IllegalStateException(
448 			"An application configuration is required to initialize the Poco::Net::SSLManager, "
449 			"but no Poco::Util::Application instance is available."
450 		);
451 	}
452 }
453 
454 
initializeSSL()455 void initializeSSL()
456 {
457 	Poco::Crypto::initializeCrypto();
458 }
459 
460 
uninitializeSSL()461 void uninitializeSSL()
462 {
463 	SSLManager::instance().shutdown();
464 	Poco::Crypto::uninitializeCrypto();
465 }
466 
467 
468 } } // namespace Poco::Net
469