From 8f764e3505c03051596f35fd58bc4f627301f0b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnter=20Obiltschnig?= Date: Tue, 6 Jun 2023 13:06:02 +0200 Subject: [PATCH] #3880: NetSSL_OpenSSL: Support session resumption with TLSv1.3 --- NetSSL_OpenSSL/include/Poco/Net/SSLManager.h | 12 +++++++ .../include/Poco/Net/SecureSocketImpl.h | 4 +++ NetSSL_OpenSSL/include/Poco/Net/Session.h | 3 ++ NetSSL_OpenSSL/src/Context.cpp | 6 ++++ NetSSL_OpenSSL/src/SecureSocketImpl.cpp | 34 +++++++++++-------- NetSSL_OpenSSL/src/Session.cpp | 17 ++++++---- .../testsuite/src/TCPServerTest.cpp | 7 ++-- 7 files changed, 58 insertions(+), 25 deletions(-) diff --git a/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h b/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h index e834a5820..9274d8b95 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h +++ b/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h @@ -287,6 +287,10 @@ protected: /// Returns the index for SSL_CTX_set_ex_data() and SSL_CTX_get_ex_data() to /// store the Context* in the underlying SSL_CTX. + int socketIndex() const; + /// Returns the index for SSL_set_ex_data() and SSL_get_ex_data() to + /// store the SecureSocketImpl* in the underlying SSL. + private: SSLManager(); /// Creates the SSLManager. @@ -320,6 +324,7 @@ private: PrivateKeyPassphraseHandlerPtr _ptrClientPassphraseHandler; InvalidCertificateHandlerPtr _ptrClientCertificateHandler; int _contextIndex; + int _socketIndex; Poco::FastMutex _mutex; static const std::string CFG_PRIV_KEY_FILE; @@ -359,6 +364,7 @@ private: friend class Poco::SingletonHolder; friend class Context; + friend class SecureSocketImpl; }; @@ -405,6 +411,12 @@ inline int SSLManager::contextIndex() const } +inline int SSLManager::socketIndex() const +{ + return _socketIndex; +} + + } } // namespace Poco::Net diff --git a/NetSSL_OpenSSL/include/Poco/Net/SecureSocketImpl.h b/NetSSL_OpenSSL/include/Poco/Net/SecureSocketImpl.h index a12447fbe..c8eedb638 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/SecureSocketImpl.h +++ b/NetSSL_OpenSSL/include/Poco/Net/SecureSocketImpl.h @@ -280,6 +280,9 @@ protected: /// Note that simply closing a socket is not sufficient /// to be able to re-use it again. + static int onSessionCreated(SSL* pSSL, SSL_SESSION* pSession); + /// Callback to handle new session data sent by server. + private: SecureSocketImpl(const SecureSocketImpl&); SecureSocketImpl& operator = (const SecureSocketImpl&); @@ -293,6 +296,7 @@ private: bool _bidirectShutdown = true; friend class SecureStreamSocketImpl; + friend class Context; }; diff --git a/NetSSL_OpenSSL/include/Poco/Net/Session.h b/NetSSL_OpenSSL/include/Poco/Net/Session.h index 465e12fdd..3ed5a4ec9 100644 --- a/NetSSL_OpenSSL/include/Poco/Net/Session.h +++ b/NetSSL_OpenSSL/include/Poco/Net/Session.h @@ -42,6 +42,9 @@ public: SSL_SESSION* sslSession() const; /// Returns the stored OpenSSL SSL_SESSION object. + bool isResumable() const; + /// Returns true if the session is resumable. + protected: Session(SSL_SESSION* pSession); /// Creates a new Session object, using the given diff --git a/NetSSL_OpenSSL/src/Context.cpp b/NetSSL_OpenSSL/src/Context.cpp index 088ba1132..5a004d8c4 100644 --- a/NetSSL_OpenSSL/src/Context.cpp +++ b/NetSSL_OpenSSL/src/Context.cpp @@ -15,6 +15,7 @@ #include "Poco/Net/Context.h" #include "Poco/Net/SSLManager.h" #include "Poco/Net/SSLException.h" +#include "Poco/Net/SecureSocketImpl.h" #include "Poco/Net/Utility.h" #include "Poco/Crypto/OpenSSLInitializer.h" #include "Poco/File.h" @@ -195,6 +196,11 @@ void Context::init(const Params& params) SSL_CTX_set_session_cache_mode(_pSSLContext, SSL_SESS_CACHE_OFF); SSL_CTX_set_ex_data(_pSSLContext, SSLManager::instance().contextIndex(), this); + if (!isForServerUse()) + { + SSL_CTX_sess_set_new_cb(_pSSLContext, &SecureSocketImpl::onSessionCreated); + } + if (!isForServerUse() && params.ocspStaplingVerification) { #if OPENSSL_VERSION_NUMBER >= 0x10001000L diff --git a/NetSSL_OpenSSL/src/SecureSocketImpl.cpp b/NetSSL_OpenSSL/src/SecureSocketImpl.cpp index e9ecdd385..14ade466c 100644 --- a/NetSSL_OpenSSL/src/SecureSocketImpl.cpp +++ b/NetSSL_OpenSSL/src/SecureSocketImpl.cpp @@ -14,6 +14,7 @@ #include "Poco/Net/SecureSocketImpl.h" #include "Poco/Net/SSLException.h" +#include "Poco/Net/SSLManager.h" #include "Poco/Net/Context.h" #include "Poco/Net/X509Certificate.h" #include "Poco/Net/Utility.h" @@ -97,6 +98,7 @@ void SecureSocketImpl::acceptSSL() } SSL_set_bio(_pSSL, pBIO, pBIO); SSL_set_accept_state(_pSSL); + SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), this); _needHandshake = true; } @@ -156,6 +158,7 @@ void SecureSocketImpl::connectSSL(bool performHandshake) throw SSLException("Cannot create SSL object"); } SSL_set_bio(_pSSL, pBIO, pBIO); + SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), this); if (!_peerHostName.empty()) { @@ -169,7 +172,7 @@ void SecureSocketImpl::connectSSL(bool performHandshake) } #endif - if (_pSession) + if (_pSession && _pSession->isResumable()) { SSL_set_session(_pSSL, _pSession->sslSession()); } @@ -609,6 +612,7 @@ void SecureSocketImpl::reset() close(); if (_pSSL) { + SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), nullptr); SSL_free(_pSSL); _pSSL = 0; } @@ -623,20 +627,7 @@ void SecureSocketImpl::abort() Session::Ptr SecureSocketImpl::currentSession() { - if (_pSSL) - { - SSL_SESSION* pSession = SSL_get1_session(_pSSL); - if (pSession) - { - if (_pSession && pSession == _pSession->sslSession()) - { - SSL_SESSION_free(pSession); - return _pSession; - } - else return new Session(pSession); - } - } - return 0; + return _pSession; } @@ -655,4 +646,17 @@ bool SecureSocketImpl::sessionWasReused() } +int SecureSocketImpl::onSessionCreated(SSL* pSSL, SSL_SESSION* pSession) +{ + void* pEx = SSL_get_ex_data(pSSL, SSLManager::instance().socketIndex()); + if (pEx) + { + SecureSocketImpl* pThis = reinterpret_cast(pEx); + pThis->_pSession = new Session(pSession); + return 1; + } + else return 0; +} + + } } // namespace Poco::Net diff --git a/NetSSL_OpenSSL/src/Session.cpp b/NetSSL_OpenSSL/src/Session.cpp index e16fc23df..c84ee9d26 100644 --- a/NetSSL_OpenSSL/src/Session.cpp +++ b/NetSSL_OpenSSL/src/Session.cpp @@ -12,13 +12,8 @@ // -#if defined(__APPLE__) -// Some OpenSSL functions are deprecated in OS X 10.7 -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - - #include "Poco/Net/Session.h" +#include namespace Poco { @@ -37,4 +32,14 @@ Session::~Session() } +bool Session::isResumable() const +{ +#if OPENSSL_VERSION_NUMBER >= 0x10101000L + return SSL_SESSION_is_resumable(_pSession) == 1; +#else + return false; +#endif +} + + } } // namespace Poco::Net diff --git a/NetSSL_OpenSSL/testsuite/src/TCPServerTest.cpp b/NetSSL_OpenSSL/testsuite/src/TCPServerTest.cpp index 9a2071bf9..1f235405d 100644 --- a/NetSSL_OpenSSL/testsuite/src/TCPServerTest.cpp +++ b/NetSSL_OpenSSL/testsuite/src/TCPServerTest.cpp @@ -370,15 +370,15 @@ void TCPServerTest::testReuseSession() ss1.useSession(pSession); ss1.connect(sa); - assertTrue (ss1.sessionWasReused()); - assertTrue (ss1.currentSession() == pSession); ss1.sendBytes(data.data(), (int) data.size()); n = ss1.receiveBytes(buffer, sizeof(buffer)); + assertTrue (ss1.sessionWasReused()); assertTrue (n > 0); assertTrue (std::string(buffer, n) == data); assertTrue (srv.currentConnections() == 1); assertTrue (srv.queuedConnections() == 0); assertTrue (srv.totalConnections() == 2); + pSession = ss1.currentSession(); ss1.close(); Thread::sleep(300); assertTrue (srv.currentConnections() == 0); @@ -388,10 +388,9 @@ void TCPServerTest::testReuseSession() ss1.useSession(pSession); ss1.connect(sa); - assertTrue (!ss1.sessionWasReused()); - assertTrue (ss1.currentSession() != pSession); ss1.sendBytes(data.data(), (int) data.size()); n = ss1.receiveBytes(buffer, sizeof(buffer)); + assertTrue (!ss1.sessionWasReused()); assertTrue (n > 0); assertTrue (std::string(buffer, n) == data); assertTrue (srv.currentConnections() == 1);