From e3d1d03c5483cad97f1c51709804c3487efe7bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Fri, 10 Jan 2020 11:41:49 +0100 Subject: [PATCH] add support for TLS 1.3 --- .../Poco/Net/CertificateHandlerFactoryMgr.h | 2 +- NetSSL_Win/include/Poco/Net/Context.h | 52 ++++-- .../include/Poco/Net/PrivateKeyFactoryMgr.h | 2 +- NetSSL_Win/include/Poco/Net/SSLManager.h | 5 +- NetSSL_Win/include/Poco/Net/Session.h | 2 +- NetSSL_Win/src/Context.cpp | 160 +++++++++++++++--- NetSSL_Win/src/SSLManager.cpp | 10 +- 7 files changed, 197 insertions(+), 36 deletions(-) diff --git a/NetSSL_Win/include/Poco/Net/CertificateHandlerFactoryMgr.h b/NetSSL_Win/include/Poco/Net/CertificateHandlerFactoryMgr.h index a087c070b..ce9b27595 100644 --- a/NetSSL_Win/include/Poco/Net/CertificateHandlerFactoryMgr.h +++ b/NetSSL_Win/include/Poco/Net/CertificateHandlerFactoryMgr.h @@ -32,7 +32,7 @@ class NetSSL_Win_API CertificateHandlerFactoryMgr /// A CertificateHandlerFactoryMgr manages all existing CertificateHandlerFactories. { public: - typedef std::map > FactoriesMap; + using FactoriesMap = std::map>; CertificateHandlerFactoryMgr(); /// Creates the CertificateHandlerFactoryMgr. diff --git a/NetSSL_Win/include/Poco/Net/Context.h b/NetSSL_Win/include/Poco/Net/Context.h index 7d2d190bd..ec53fbc79 100644 --- a/NetSSL_Win/include/Poco/Net/Context.h +++ b/NetSSL_Win/include/Poco/Net/Context.h @@ -50,18 +50,22 @@ class NetSSL_Win_API Context: public Poco::RefCountedObject /// SSL session caching on the server and client side. { public: - typedef Poco::AutoPtr Ptr; + using Ptr = Poco::AutoPtr; enum Usage { - CLIENT_USE, /// Context is used by a client. - SERVER_USE, /// Context is used by a server. - TLSV1_CLIENT_USE, /// Context is used by a client requiring TLSv1. - TLSV1_SERVER_USE, /// Context is used by a server requiring TLSv1. - TLSV1_1_CLIENT_USE, /// Context is used by a client requiring TLSv1.1. Not supported on Windows Embedded Compact. - TLSV1_1_SERVER_USE, /// Context is used by a server requiring TLSv1.1. Not supported on Windows Embedded Compact. - TLSV1_2_CLIENT_USE, /// Context is used by a client requiring TLSv1.2. Not supported on Windows Embedded Compact. - TLSV1_2_SERVER_USE /// Context is used by a server requiring TLSv1.2. Not supported on Windows Embedded Compact. + TLS_CLIENT_USE, /// Context is used by a client for TLSv1 or higher. Use requireMinimumProtocol() or disableProtocols() to disable undesired older versions. + TLS_SERVER_USE, /// Context is used by a client for TLSv1 or higher. Use requireMinimumProtocol() or disableProtocols() to disable undesired older versions. + CLIENT_USE, /// DEPRECATED. Context is used by a client. + SERVER_USE, /// DEPRECATED. Context is used by a server. + TLSV1_CLIENT_USE, /// DEPRECATED. Context is used by a client requiring TLSv1. + TLSV1_SERVER_USE, /// DEPRECATED. Context is used by a server requiring TLSv1. + TLSV1_1_CLIENT_USE, /// DEPRECATED. Context is used by a client requiring TLSv1.1. Not supported on Windows Embedded Compact. + TLSV1_1_SERVER_USE, /// DEPRECATED. Context is used by a server requiring TLSv1.1. Not supported on Windows Embedded Compact. + TLSV1_2_CLIENT_USE, /// DEPRECATED. Context is used by a client requiring TLSv1.2. Not supported on Windows Embedded Compact. + TLSV1_2_SERVER_USE, /// DEPRECATED. Context is used by a server requiring TLSv1.2. Not supported on Windows Embedded Compact. + TLSV1_3_CLIENT_USE, /// DEPRECATED. Context is used by a client requiring TLSv1.3. Not supported on Windows Embedded Compact. + TLSV1_3_SERVER_USE /// DEPRECATED. Context is used by a server requiring TLSv1.3. Not supported on Windows Embedded Compact. }; enum VerificationMode @@ -98,6 +102,16 @@ public: /// the OpenSSL implementation. }; + enum Protocols + { + PROTO_SSLV2 = 0x01, + PROTO_SSLV3 = 0x02, + PROTO_TLSV1 = 0x04, + PROTO_TLSV1_1 = 0x08, + PROTO_TLSV1_2 = 0x10, + PROTO_TLSV1_3 = 0x20 + }; + enum Options { OPT_PERFORM_REVOCATION_CHECK = 0x01, @@ -173,6 +187,20 @@ public: void addTrustedCert(const Poco::Net::X509Certificate& cert); /// Adds the certificate to the trusted certs. Takes ownership of pCert. + void disableProtocols(int protocols); + /// Disables the given protocols. + /// + /// The protocols to be disabled are specified by OR-ing + /// values from the Protocols enumeration, e.g.: + /// + /// context.disableProtocols(PROTO_SSLV2 | PROTO_SSLV3); + + void requireMinimumProtocol(Protocols protocol); + /// Disables all protocol version lower than the given one. + /// To require at least TLS 1.2 or later: + /// + /// context.requireMinimumProtocol(PROTO_TLSV1_2); + Poco::Net::X509Certificate certificate(); /// Loads or imports and returns the certificate specified in the constructor. /// @@ -201,6 +229,7 @@ protected: void importCertificate(const char* pBuffer, std::size_t size); void acquireSchannelCredentials(CredHandle& credHandle) const; DWORD proto() const; + DWORD enabledProtocols() const; private: Context(const Context&); @@ -209,6 +238,7 @@ private: Usage _usage; Context::VerificationMode _mode; int _options; + int _disabledProtocols; bool _extendedCertificateVerification; std::string _certNameOrPath; std::string _certStoreName; @@ -247,9 +277,11 @@ inline int Context::options() const inline bool Context::isForServerUse() const { return _usage == SERVER_USE + || _usage == TLS_SERVER_USE || _usage == TLSV1_SERVER_USE || _usage == TLSV1_1_SERVER_USE - || _usage == TLSV1_2_SERVER_USE; + || _usage == TLSV1_2_SERVER_USE + || _usage == TLSV1_3_SERVER_USE; } diff --git a/NetSSL_Win/include/Poco/Net/PrivateKeyFactoryMgr.h b/NetSSL_Win/include/Poco/Net/PrivateKeyFactoryMgr.h index 07afb2336..bfde829d1 100644 --- a/NetSSL_Win/include/Poco/Net/PrivateKeyFactoryMgr.h +++ b/NetSSL_Win/include/Poco/Net/PrivateKeyFactoryMgr.h @@ -32,7 +32,7 @@ class NetSSL_Win_API PrivateKeyFactoryMgr /// A PrivateKeyFactoryMgr manages all existing PrivateKeyFactories. { public: - typedef std::map > FactoriesMap; + using FactoriesMap = std::map>; PrivateKeyFactoryMgr(); /// Creates the PrivateKeyFactoryMgr. diff --git a/NetSSL_Win/include/Poco/Net/SSLManager.h b/NetSSL_Win/include/Poco/Net/SSLManager.h index db5d9b0a7..6122a06ac 100644 --- a/NetSSL_Win/include/Poco/Net/SSLManager.h +++ b/NetSSL_Win/include/Poco/Net/SSLManager.h @@ -126,8 +126,8 @@ class NetSSL_Win_API SSLManager /// - requireTLSv1_2 (boolean): Require a TLSv1.2 connection. Not supported on Windows Embedded Compact. { public: - typedef Poco::SharedPtr PrivateKeyPassphraseHandlerPtr; - typedef Poco::SharedPtr InvalidCertificateHandlerPtr; + using PrivateKeyPassphraseHandlerPtr = Poco::SharedPtr; + using InvalidCertificateHandlerPtr = Poco::SharedPtr; Poco::BasicEvent ServerVerificationError; /// Fired whenever a certificate verification error is detected by the server during a handshake. @@ -292,6 +292,7 @@ private: static const std::string CFG_REQUIRE_TLSV1; static const std::string CFG_REQUIRE_TLSV1_1; static const std::string CFG_REQUIRE_TLSV1_2; + static const std::string CFG_REQUIRE_TLSV1_3; friend class Poco::SingletonHolder; friend class SecureSocketImpl; diff --git a/NetSSL_Win/include/Poco/Net/Session.h b/NetSSL_Win/include/Poco/Net/Session.h index c54253aa6..3582fc1d9 100644 --- a/NetSSL_Win/include/Poco/Net/Session.h +++ b/NetSSL_Win/include/Poco/Net/Session.h @@ -36,7 +36,7 @@ class NetSSL_Win_API Session: public Poco::RefCountedObject /// if it wants to reuse it with a future connection. { public: - typedef Poco::AutoPtr Ptr; + using Ptr = Poco::AutoPtr; protected: Session(); diff --git a/NetSSL_Win/src/Context.cpp b/NetSSL_Win/src/Context.cpp index c1b27bb20..1d5bfc488 100644 --- a/NetSSL_Win/src/Context.cpp +++ b/NetSSL_Win/src/Context.cpp @@ -46,6 +46,7 @@ Context::Context(Usage usage, _usage(usage), _mode(verMode), _options(options), + _disabledProtocols(0), _extendedCertificateVerification(true), _certNameOrPath(certNameOrPath), _certStoreName(certStore), @@ -312,15 +313,15 @@ void Context::acquireSchannelCredentials(CredHandle& credHandle) const TimeStamp tsExpiry; tsExpiry.LowPart = tsExpiry.HighPart = 0; SECURITY_STATUS status = _securityFunctions.AcquireCredentialsHandleW( - NULL, - UNISP_NAME_W, - isForServerUse() ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, - NULL, - &schannelCred, - NULL, - NULL, - &credHandle, - &tsExpiry); + NULL, + UNISP_NAME_W, + isForServerUse() ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, + NULL, + &schannelCred, + NULL, + NULL, + &credHandle, + &tsExpiry); if (status != SEC_E_OK) { @@ -331,69 +332,190 @@ void Context::acquireSchannelCredentials(CredHandle& credHandle) const DWORD Context::proto() const { + DWORD result = 0; switch (_usage) { + case Context::TLS_CLIENT_USE: case Context::CLIENT_USE: - return SP_PROT_SSL3_CLIENT + result = SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_CLIENT #if defined(SP_PROT_TLS1_1) | SP_PROT_TLS1_1_CLIENT #endif #if defined(SP_PROT_TLS1_2) | SP_PROT_TLS1_2_CLIENT +#endif +#if defined(SP_PROT_TLS1_3) + | SP_PROT_TLS1_3_CLIENT #endif ; + break; + + case Context::TLS_SERVER_USE: case Context::SERVER_USE: - return SP_PROT_SSL3_SERVER + result = SP_PROT_SSL3_SERVER | SP_PROT_TLS1_SERVER #if defined(SP_PROT_TLS1_1) | SP_PROT_TLS1_1_SERVER #endif #if defined(SP_PROT_TLS1_2) | SP_PROT_TLS1_2_SERVER +#endif +#if defined(SP_PROT_TLS1_3) + | SP_PROT_TLS1_3_SERVER #endif ; + break; + case Context::TLSV1_CLIENT_USE: - return SP_PROT_TLS1_CLIENT + result = SP_PROT_TLS1_CLIENT #if defined(SP_PROT_TLS1_1) | SP_PROT_TLS1_1_CLIENT #endif #if defined(SP_PROT_TLS1_2) | SP_PROT_TLS1_2_CLIENT +#endif +#if defined(SP_PROT_TLS1_3) + | SP_PROT_TLS1_3_CLIENT #endif ; + break; + case Context::TLSV1_SERVER_USE: - return SP_PROT_TLS1_SERVER + result = SP_PROT_TLS1_SERVER #if defined(SP_PROT_TLS1_1) | SP_PROT_TLS1_1_SERVER #endif #if defined(SP_PROT_TLS1_2) | SP_PROT_TLS1_2_SERVER +#endif +#if defined(SP_PROT_TLS1_3) + | SP_PROT_TLS1_3_SERVER #endif ; + break; + #if defined(SP_PROT_TLS1_1) case Context::TLSV1_1_CLIENT_USE: - return SP_PROT_TLS1_1_CLIENT + result = SP_PROT_TLS1_1_CLIENT #if defined(SP_PROT_TLS1_2) | SP_PROT_TLS1_2_CLIENT +#endif +#if defined(SP_PROT_TLS1_3) + | SP_PROT_TLS1_3_CLIENT #endif ; + break; + case Context::TLSV1_1_SERVER_USE: - return SP_PROT_TLS1_1_SERVER + result = SP_PROT_TLS1_1_SERVER #if defined(SP_PROT_TLS1_2) | SP_PROT_TLS1_2_SERVER #endif - ; +#if defined(SP_PROT_TLS1_3) + | SP_PROT_TLS1_3_SERVER #endif + ; + break; +#endif + #if defined(SP_PROT_TLS1_2) case Context::TLSV1_2_CLIENT_USE: - return SP_PROT_TLS1_2_CLIENT; - case Context::TLSV1_2_SERVER_USE: - return SP_PROT_TLS1_2_SERVER; + result = SP_PROT_TLS1_2_CLIENT +#if defined(SP_PROT_TLS1_3) + | SP_PROT_TLS1_3_CLIENT #endif + ; + break; + + case Context::TLSV1_2_SERVER_USE: + result = SP_PROT_TLS1_2_SERVER +#if defined(SP_PROT_TLS1_3) + | SP_PROT_TLS1_3_SERVER +#endif + ; + break; +#endif + +#if defined(SP_PROT_TLS1_3) + case Context::TLSV1_3_CLIENT_USE: + result = SP_PROT_TLS1_3_CLIENT; + break; + + case Context::TLSV1_3_SERVER_USE: + result = SP_PROT_TLS1_3_SERVER; + break; +#endif + default: throw Poco::InvalidArgumentException("Unsupported SSL/TLS protocol version"); } + + return result & enabledProtocols(); } + +DWORD Context::enabledProtocols() const +{ + DWORD result = 0; + if (!(_disabledProtocols & PROTO_SSLV3)) + { + result |= SP_PROT_SSL3_CLIENT | SP_PROT_SSL3_SERVER; + } + if (!(_disabledProtocols & PROTO_TLSV1)) + { + result |= SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_SERVER; + } + if (!(_disabledProtocols & PROTO_TLSV1_1)) + { +#ifdef SP_PROT_TLS1_1_CLIENT + result |= SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_1_SERVER; +#endif + } + if (!(_disabledProtocols & PROTO_TLSV1_2)) + { +#ifdef SP_PROT_TLS1_2_CLIENT + result |= SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_2_SERVER; +#endif + } + if (!(_disabledProtocols & PROTO_TLSV1_3)) + { +#ifdef SP_PROT_TLS1_3_CLIENT + result |= SP_PROT_TLS1_3_CLIENT | SP_PROT_TLS1_3_SERVER; +#endif + } + return result; +} + + +void Context::disableProtocols(int protocols) +{ + _disabledProtocols = protocols; +} + + +void Context::requireMinimumProtocol(Protocols protocol) +{ + _disabledProtocols = 0; + switch (protocol) + { + case PROTO_SSLV3: + _disabledProtocols = PROTO_SSLV2; + break; + case PROTO_TLSV1: + _disabledProtocols = PROTO_SSLV2 | PROTO_SSLV3; + break; + case PROTO_TLSV1_1: + _disabledProtocols = PROTO_SSLV2 | PROTO_SSLV3 | PROTO_TLSV1; + break; + case PROTO_TLSV1_2: + _disabledProtocols = PROTO_SSLV2 | PROTO_SSLV3 | PROTO_TLSV1 | PROTO_TLSV1_1; + break; + case PROTO_TLSV1_3: + _disabledProtocols = PROTO_SSLV2 | PROTO_SSLV3 | PROTO_TLSV1 | PROTO_TLSV1_1 | PROTO_TLSV1_2; + break; + } +} + + } } // namespace Poco::Net diff --git a/NetSSL_Win/src/SSLManager.cpp b/NetSSL_Win/src/SSLManager.cpp index 1e6f0fa22..fbabfcb03 100644 --- a/NetSSL_Win/src/SSLManager.cpp +++ b/NetSSL_Win/src/SSLManager.cpp @@ -52,6 +52,7 @@ const std::string SSLManager::CFG_CLIENT_PREFIX("schannel.client."); const std::string SSLManager::CFG_REQUIRE_TLSV1("requireTLSv1"); const std::string SSLManager::CFG_REQUIRE_TLSV1_1("requireTLSv1_1"); const std::string SSLManager::CFG_REQUIRE_TLSV1_2("requireTLSv1_2"); +const std::string SSLManager::CFG_REQUIRE_TLSV1_3("requireTLSv1_3"); SSLManager::SSLManager(): @@ -195,6 +196,7 @@ void SSLManager::initDefaultContext(bool server) bool requireTLSv1 = config.getBool(prefix + CFG_REQUIRE_TLSV1, false); bool requireTLSv1_1 = config.getBool(prefix + CFG_REQUIRE_TLSV1_1, false); bool requireTLSv1_2 = config.getBool(prefix + CFG_REQUIRE_TLSV1_2, false); + bool requireTLSv1_3 = config.getBool(prefix + CFG_REQUIRE_TLSV1_3, false); // optional options for which we have defaults defined Context::VerificationMode verMode = VAL_VER_MODE; @@ -223,7 +225,9 @@ void SSLManager::initDefaultContext(bool server) Context::Usage usage; if (server) { - if (requireTLSv1_2) + if (requireTLSv1_3) + usage = Context::TLSV1_3_SERVER_USE; + else if (requireTLSv1_2) usage = Context::TLSV1_2_SERVER_USE; else if (requireTLSv1_1) usage = Context::TLSV1_1_SERVER_USE; @@ -235,7 +239,9 @@ void SSLManager::initDefaultContext(bool server) } else { - if (requireTLSv1_2) + if (requireTLSv1_3) + usage = Context::TLSV1_3_CLIENT_USE; + else if (requireTLSv1_2) usage = Context::TLSV1_2_CLIENT_USE; else if (requireTLSv1_1) usage = Context::TLSV1_1_CLIENT_USE;