From 6000982c8b5210712f5c7456c1b6b78c33bae279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Fri, 24 Aug 2018 10:47:05 +0200 Subject: [PATCH] added preliminary TLSv1.3 support with OpenSSL version 1.1.1 --- NetSSL_OpenSSL/include/Poco/Net/Context.h | 24 ++++++++++- NetSSL_OpenSSL/include/Poco/Net/SSLManager.h | 45 +++++++++++--------- NetSSL_OpenSSL/src/Context.cpp | 14 ++++++ NetSSL_OpenSSL/src/SSLManager.cpp | 28 +++++++----- 4 files changed, 79 insertions(+), 32 deletions(-) diff --git a/NetSSL_OpenSSL/include/Poco/Net/Context.h b/NetSSL_OpenSSL/include/Poco/Net/Context.h index c239d52b4..f0a652fb3 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/Context.h +++ b/NetSSL_OpenSSL/include/Poco/Net/Context.h @@ -42,6 +42,23 @@ class NetSSL_API Context: public Poco::RefCountedObject /// /// The Context class is also used to control /// SSL session caching on the server and client side. + /// + /// A Note Regarding TLSv1.3 Support: + /// + /// TLSv1.3 support requires at least OpenSSL version 1.1.1. + /// In order to enable TLSv1.3 support, specify TLSV1_3_CLIENT_USE + /// or TLSV1_3_SERVER_USE and make sure that the TLSv1.3 + /// cipher suites are enabled: + /// + /// - TLS_AES_256_GCM_SHA384 + /// - TLS_CHACHA20_POLY1305_SHA256 + /// - TLS_AES_128_GCM_SHA256 + /// - TLS_AES_128_CCM_8_SHA256 + /// - TLS_AES_128_CCM_SHA256 + /// + /// The first three of the above cipher suites should be enabled + /// by default in OpenSSL if you do not provide an explicit + /// cipher configuration (cipherList). { public: typedef Poco::AutoPtr Ptr; @@ -55,7 +72,9 @@ public: TLSV1_1_CLIENT_USE, /// Context is used by a client requiring TLSv1.1 (OpenSSL 1.0.0 or newer). TLSV1_1_SERVER_USE, /// Context is used by a server requiring TLSv1.1 (OpenSSL 1.0.0 or newer). TLSV1_2_CLIENT_USE, /// Context is used by a client requiring TLSv1.2 (OpenSSL 1.0.1 or newer). - TLSV1_2_SERVER_USE /// Context is used by a server requiring TLSv1.2 (OpenSSL 1.0.1 or newer). + TLSV1_2_SERVER_USE, /// Context is used by a server requiring TLSv1.2 (OpenSSL 1.0.1 or newer). + TLSV1_3_CLIENT_USE, /// Context is used by a client requiring TLSv1.3 (OpenSSL 1.1.1 or newer). + TLSV1_3_SERVER_USE /// Context is used by a server requiring TLSv1.3 (OpenSSL 1.1.1 or newer). }; enum VerificationMode @@ -101,7 +120,8 @@ public: PROTO_SSLV3 = 0x02, PROTO_TLSV1 = 0x04, PROTO_TLSV1_1 = 0x08, - PROTO_TLSV1_2 = 0x10 + PROTO_TLSV1_2 = 0x10, + PROTO_TLSV1_3 = 0x20 }; struct NetSSL_API Params diff --git a/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h b/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h index 7e441e6f9..343d933a9 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h +++ b/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h @@ -42,7 +42,7 @@ class Context; class NetSSL_API SSLManager - /// SSLManager is a singleton for holding the default server/client + /// SSLManager is a singleton for holding the default server/client /// Context and handling callbacks for certificate verification errors /// and private key passphrases. /// @@ -62,7 +62,7 @@ class NetSSL_API SSLManager /// ClientVerificationError and PrivateKeyPassphraseRequired events /// must be registered. /// - /// An exemplary documentation which sets either the server or client default context and creates + /// An exemplary documentation which sets either the server or client default context and creates /// a PrivateKeyPassphraseHandler that reads the password from the XML file looks like this: /// /// @@ -93,7 +93,8 @@ class NetSSL_API SSLManager /// true|false /// true|false /// true|false - /// sslv2,sslv3,tlsv1,tlsv1_1,tlsv1_2 + /// true|false + /// sslv2,sslv3,tlsv1,tlsv1_1,tlsv1_2,tlsv1_3 /// dh.pem /// prime256v1 /// @@ -104,7 +105,7 @@ class NetSSL_API SSLManager /// Following is a list of supported configuration properties. Property names must always /// be prefixed with openSSL.server or openSSL.client. Some properties are only supported /// for servers. - /// + /// /// - privateKeyFile (string): The path to the file containing the private key for the certificate /// in PEM format (or containing both the private key and the certificate). /// - certificateFile (string): The Path to the file containing the server's or client's certificate @@ -117,9 +118,9 @@ class NetSSL_API SSLManager /// - loadDefaultCAFile (boolean): Specifies whether the builtin CA certificates from OpenSSL are used. /// - cipherList (string): Specifies the supported ciphers in OpenSSL notation /// (e.g. "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"). - /// - preferServerCiphers (bool): When choosing a cipher, use the server's preferences instead of the - /// client preferences. When not called, the SSL server will always follow the clients - /// preferences. When called, the SSL/TLS server will choose following its own + /// - preferServerCiphers (bool): When choosing a cipher, use the server's preferences instead of the + /// client preferences. When not called, the SSL server will always follow the clients + /// preferences. When called, the SSL/TLS server will choose following its own /// preferences. /// - privateKeyPassphraseHandler.name (string): The name of the class (subclass of PrivateKeyPassphraseHandler) /// used for obtaining the passphrase for accessing the private key. @@ -127,14 +128,14 @@ class NetSSL_API SSLManager /// - invalidCertificateHandler.name: The name of the class (subclass of CertificateHandler) /// used for confirming invalid certificates. /// - cacheSessions (boolean): Enables or disables session caching. - /// - sessionIdContext (string): contains the application's unique session ID context, which becomes - /// part of each session identifier generated by the server. Can be an arbitrary sequence + /// - sessionIdContext (string): contains the application's unique session ID context, which becomes + /// part of each session identifier generated by the server. Can be an arbitrary sequence /// of bytes with a maximum length of SSL_MAX_SSL_SESSION_ID_LENGTH. Should be specified /// for a server to enable session caching. Should be specified even if session caching /// is disabled to avoid problems with clients that request session caching (e.g. Firefox 3.6). /// If not specified, defaults to ${application.name}. /// - sessionCacheSize (integer): Sets the maximum size of the server session cache, in number of - /// sessions. The default size (according to OpenSSL documentation) is 1024*20, which may be too + /// sessions. The default size (according to OpenSSL documentation) is 1024*20, which may be too /// large for many applications, especially on embedded platforms with limited memory. /// Specifying a size of 0 will set an unlimited cache size. /// - sessionTimeout (integer): Sets the timeout (in seconds) of cached sessions on the server. @@ -143,14 +144,17 @@ class NetSSL_API SSLManager /// - requireTLSv1 (boolean): Require a TLSv1 connection. /// - requireTLSv1_1 (boolean): Require a TLSv1.1 connection. /// - requireTLSv1_2 (boolean): Require a TLSv1.2 connection. + /// - requireTLSv1_3 (boolean): Require a TLSv1.3 connection /// - disableProtocols (string): A comma-separated list of protocols that should be - /// disabled. Valid protocol names are sslv2, sslv3, tlsv1, tlsv1_1, tlsv1_2. + /// disabled. Valid protocol names are sslv2, sslv3, tlsv1, tlsv1_1, tlsv1_2, tlsv1_3. /// - dhParamsFile (string): Specifies a file containing Diffie-Hellman parameters. /// If not specified or empty, the default parameters are used. /// - ecdhCurve (string): Specifies the name of the curve to use for ECDH, based /// on the curve names specified in RFC 4492. Defaults to "prime256v1". - /// - fips: Enable or disable OpenSSL FIPS mode. Only supported if the OpenSSL version + /// - fips: Enable or disable OpenSSL FIPS mode. Only supported if the OpenSSL version /// that this library is built against supports FIPS mode. + /// + /// Please see the Context class documentation regarding TLSv1.3 support. { public: typedef Poco::SharedPtr PrivateKeyPassphraseHandlerPtr; @@ -176,7 +180,7 @@ public: /// PtrPassphraseHandler and ptrCertificateHandler can be 0. However, in this case, event delegates /// must be registered with the ServerVerificationError and PrivateKeyPassphraseRequired events. /// - /// Note: Always create the handlers (or register the corresponding event delegates) before creating + /// Note: Always create the handlers (or register the corresponding event delegates) before creating /// the Context, as during creation of the Context the passphrase for the private key might be needed. /// /// Valid initialization code would be: @@ -192,7 +196,7 @@ public: /// PtrPassphraseHandler and ptrCertificateHandler can be 0. However, in this case, event delegates /// must be registered with the ClientVerificationError and PrivateKeyPassphraseRequired events. /// - /// Note: Always create the handlers (or register the corresponding event delegates) before creating + /// Note: Always create the handlers (or register the corresponding event delegates) before creating /// the Context, as during creation of the Context the passphrase for the private key might be needed. /// /// Valid initialization code would be: @@ -202,13 +206,13 @@ public: /// SSLManager::instance().initializeClient(pConsoleHandler, pInvalidCertHandler, pContext); Context::Ptr defaultServerContext(); - /// Returns the default Context used by the server. + /// Returns the default Context used by the server. /// /// Unless initializeServer() has been called, the first call to this method initializes the default Context /// from the application configuration. Context::Ptr defaultClientContext(); - /// Returns the default Context used by the client. + /// Returns the default Context used by the client. /// /// Unless initializeClient() has been called, the first call to this method initializes the default Context /// from the application configuration. @@ -230,16 +234,16 @@ public: /// If none is set, it will try to auto-initialize one from an application configuration. PrivateKeyFactoryMgr& privateKeyFactoryMgr(); - /// Returns the private key factory manager which stores the + /// Returns the private key factory manager which stores the /// factories for the different registered passphrase handlers for private keys. CertificateHandlerFactoryMgr& certificateHandlerFactoryMgr(); - /// Returns the CertificateHandlerFactoryMgr which stores the + /// Returns the CertificateHandlerFactoryMgr which stores the /// factories for the different registered certificate handlers. static bool isFIPSEnabled(); // Returns true if FIPS mode is enabled, false otherwise. - + void shutdown(); /// Shuts down the SSLManager and releases the default Context /// objects. After a call to shutdown(), the SSLManager can no @@ -267,7 +271,7 @@ protected: /// Method is invoked by OpenSSL to retrieve a passwd for an encrypted certificate. /// The request is delegated to the PrivatekeyPassword event. This method returns the /// length of the password. - + static Poco::Util::AbstractConfiguration& appConfig(); /// Returns the application configuration. /// @@ -333,6 +337,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; static const std::string CFG_DISABLE_PROTOCOLS; static const std::string CFG_DH_PARAMS_FILE; static const std::string CFG_ECDH_CURVE; diff --git a/NetSSL_OpenSSL/src/Context.cpp b/NetSSL_OpenSSL/src/Context.cpp index 575276405..5f625a255 100644 --- a/NetSSL_OpenSSL/src/Context.cpp +++ b/NetSSL_OpenSSL/src/Context.cpp @@ -372,6 +372,12 @@ void Context::disableProtocols(int protocols) { #if defined(SSL_OP_NO_TLSv1_2) SSL_CTX_set_options(_pSSLContext, SSL_OP_NO_TLSv1_2); +#endif + } + if (protocols & PROTO_TLSV1_3) + { +#if defined(SSL_OP_NO_TLSv1_3) + SSL_CTX_set_options(_pSSLContext, SSL_OP_NO_TLSv1_3); #endif } } @@ -436,6 +442,14 @@ void Context::createSSLContext() case TLSV1_2_SERVER_USE: _pSSLContext = SSL_CTX_new(TLSv1_2_server_method()); break; +#endif +#if defined(SSL_OP_NO_TLSv1_3) && !defined(OPENSSL_NO_TLS1) + case TLSV1_3_CLIENT_USE: + _pSSLContext = SSL_CTX_new(TLS_client_method()); + break; + case TLSV1_3_SERVER_USE: + _pSSLContext = SSL_CTX_new(TLS_server_method()); + break; #endif default: throw Poco::InvalidArgumentException("Invalid or unsupported usage"); diff --git a/NetSSL_OpenSSL/src/SSLManager.cpp b/NetSSL_OpenSSL/src/SSLManager.cpp index 82eed1a29..bf5ef4600 100644 --- a/NetSSL_OpenSSL/src/SSLManager.cpp +++ b/NetSSL_OpenSSL/src/SSLManager.cpp @@ -57,6 +57,7 @@ const std::string SSLManager::CFG_EXTENDED_VERIFICATION("extendedVerification"); 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"); const std::string SSLManager::CFG_DISABLE_PROTOCOLS("disableProtocols"); const std::string SSLManager::CFG_DH_PARAMS_FILE("dhParamsFile"); const std::string SSLManager::CFG_ECDH_CURVE("ecdhCurve"); @@ -125,7 +126,7 @@ void SSLManager::initializeClient(PrivateKeyPassphraseHandlerPtr ptrPassphraseHa Context::Ptr SSLManager::defaultServerContext() { Poco::FastMutex::ScopedLock lock(_mutex); - + if (!_ptrDefaultServerContext) initDefaultContext(true); @@ -150,7 +151,7 @@ Context::Ptr SSLManager::defaultClientContext() _ptrDefaultClientContext->disableProtocols(Context::PROTO_SSLV2 | Context::PROTO_SSLV3); } } - + return _ptrDefaultClientContext; } @@ -256,7 +257,7 @@ void SSLManager::initDefaultContext(bool server) Context::Params params; // mandatory options params.privateKeyFile = config.getString(prefix + CFG_PRIV_KEY_FILE, ""); - params.certificateFile = config.getString(prefix + CFG_CERTIFICATE_FILE, params.privateKeyFile); + params.certificateFile = config.getString(prefix + CFG_CERTIFICATE_FILE, params.privateKeyFile); params.caLocation = config.getString(prefix + CFG_CA_LOCATION, ""); if (server && params.certificateFile.empty() && params.privateKeyFile.empty()) @@ -278,15 +279,18 @@ 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); params.dhParamsFile = config.getString(prefix + CFG_DH_PARAMS_FILE, ""); params.ecdhCurve = config.getString(prefix + CFG_ECDH_CURVE, ""); 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; @@ -298,7 +302,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; @@ -308,7 +314,7 @@ void SSLManager::initDefaultContext(bool server) usage = Context::CLIENT_USE; _ptrDefaultClientContext = new Context(usage, params); } - + std::string disabledProtocolsList = config.getString(prefix + CFG_DISABLE_PROTOCOLS, ""); Poco::StringTokenizer dpTok(disabledProtocolsList, ";,", Poco::StringTokenizer::TOK_TRIM | Poco::StringTokenizer::TOK_IGNORE_EMPTY); int disabledProtocols = 0; @@ -324,12 +330,14 @@ void SSLManager::initDefaultContext(bool server) disabledProtocols |= Context::PROTO_TLSV1_1; else if (*it == "tlsv1_2") disabledProtocols |= Context::PROTO_TLSV1_2; + else if (*it == "tlsv1_3") + disabledProtocols |= Context::PROTO_TLSV1_3; } if (server) _ptrDefaultServerContext->disableProtocols(disabledProtocols); else _ptrDefaultClientContext->disableProtocols(disabledProtocols); - + bool cacheSessions = config.getBool(prefix + CFG_CACHE_SESSIONS, false); if (server) { @@ -378,7 +386,7 @@ void SSLManager::initPassphraseHandler(bool server) { if (server && _ptrServerPassphraseHandler) return; if (!server && _ptrClientPassphraseHandler) return; - + std::string prefix = server ? CFG_SERVER_PREFIX : CFG_CLIENT_PREFIX; Poco::Util::AbstractConfiguration& config = appConfig(); @@ -399,7 +407,7 @@ void SSLManager::initPassphraseHandler(bool server) } else throw Poco::Util::UnknownOptionException(std::string("No passphrase handler known with the name ") + className); } - + void SSLManager::initCertificateHandler(bool server) {