#3880: NetSSL_OpenSSL: Support session resumption with TLSv1.3

This commit is contained in:
Günter Obiltschnig 2023-06-06 13:06:02 +02:00
parent a9ad113742
commit 8f764e3505
7 changed files with 58 additions and 25 deletions

View File

@ -287,6 +287,10 @@ protected:
/// Returns the index for SSL_CTX_set_ex_data() and SSL_CTX_get_ex_data() to /// Returns the index for SSL_CTX_set_ex_data() and SSL_CTX_get_ex_data() to
/// store the Context* in the underlying SSL_CTX. /// 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: private:
SSLManager(); SSLManager();
/// Creates the SSLManager. /// Creates the SSLManager.
@ -320,6 +324,7 @@ private:
PrivateKeyPassphraseHandlerPtr _ptrClientPassphraseHandler; PrivateKeyPassphraseHandlerPtr _ptrClientPassphraseHandler;
InvalidCertificateHandlerPtr _ptrClientCertificateHandler; InvalidCertificateHandlerPtr _ptrClientCertificateHandler;
int _contextIndex; int _contextIndex;
int _socketIndex;
Poco::FastMutex _mutex; Poco::FastMutex _mutex;
static const std::string CFG_PRIV_KEY_FILE; static const std::string CFG_PRIV_KEY_FILE;
@ -359,6 +364,7 @@ private:
friend class Poco::SingletonHolder<SSLManager>; friend class Poco::SingletonHolder<SSLManager>;
friend class Context; 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 } } // namespace Poco::Net

View File

@ -280,6 +280,9 @@ protected:
/// Note that simply closing a socket is not sufficient /// Note that simply closing a socket is not sufficient
/// to be able to re-use it again. /// 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: private:
SecureSocketImpl(const SecureSocketImpl&); SecureSocketImpl(const SecureSocketImpl&);
SecureSocketImpl& operator = (const SecureSocketImpl&); SecureSocketImpl& operator = (const SecureSocketImpl&);
@ -293,6 +296,7 @@ private:
bool _bidirectShutdown = true; bool _bidirectShutdown = true;
friend class SecureStreamSocketImpl; friend class SecureStreamSocketImpl;
friend class Context;
}; };

View File

@ -42,6 +42,9 @@ public:
SSL_SESSION* sslSession() const; SSL_SESSION* sslSession() const;
/// Returns the stored OpenSSL SSL_SESSION object. /// Returns the stored OpenSSL SSL_SESSION object.
bool isResumable() const;
/// Returns true if the session is resumable.
protected: protected:
Session(SSL_SESSION* pSession); Session(SSL_SESSION* pSession);
/// Creates a new Session object, using the given /// Creates a new Session object, using the given

View File

@ -15,6 +15,7 @@
#include "Poco/Net/Context.h" #include "Poco/Net/Context.h"
#include "Poco/Net/SSLManager.h" #include "Poco/Net/SSLManager.h"
#include "Poco/Net/SSLException.h" #include "Poco/Net/SSLException.h"
#include "Poco/Net/SecureSocketImpl.h"
#include "Poco/Net/Utility.h" #include "Poco/Net/Utility.h"
#include "Poco/Crypto/OpenSSLInitializer.h" #include "Poco/Crypto/OpenSSLInitializer.h"
#include "Poco/File.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_session_cache_mode(_pSSLContext, SSL_SESS_CACHE_OFF);
SSL_CTX_set_ex_data(_pSSLContext, SSLManager::instance().contextIndex(), this); 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 (!isForServerUse() && params.ocspStaplingVerification)
{ {
#if OPENSSL_VERSION_NUMBER >= 0x10001000L #if OPENSSL_VERSION_NUMBER >= 0x10001000L

View File

@ -14,6 +14,7 @@
#include "Poco/Net/SecureSocketImpl.h" #include "Poco/Net/SecureSocketImpl.h"
#include "Poco/Net/SSLException.h" #include "Poco/Net/SSLException.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/Context.h" #include "Poco/Net/Context.h"
#include "Poco/Net/X509Certificate.h" #include "Poco/Net/X509Certificate.h"
#include "Poco/Net/Utility.h" #include "Poco/Net/Utility.h"
@ -97,6 +98,7 @@ void SecureSocketImpl::acceptSSL()
} }
SSL_set_bio(_pSSL, pBIO, pBIO); SSL_set_bio(_pSSL, pBIO, pBIO);
SSL_set_accept_state(_pSSL); SSL_set_accept_state(_pSSL);
SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), this);
_needHandshake = true; _needHandshake = true;
} }
@ -156,6 +158,7 @@ void SecureSocketImpl::connectSSL(bool performHandshake)
throw SSLException("Cannot create SSL object"); throw SSLException("Cannot create SSL object");
} }
SSL_set_bio(_pSSL, pBIO, pBIO); SSL_set_bio(_pSSL, pBIO, pBIO);
SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), this);
if (!_peerHostName.empty()) if (!_peerHostName.empty())
{ {
@ -169,7 +172,7 @@ void SecureSocketImpl::connectSSL(bool performHandshake)
} }
#endif #endif
if (_pSession) if (_pSession && _pSession->isResumable())
{ {
SSL_set_session(_pSSL, _pSession->sslSession()); SSL_set_session(_pSSL, _pSession->sslSession());
} }
@ -609,6 +612,7 @@ void SecureSocketImpl::reset()
close(); close();
if (_pSSL) if (_pSSL)
{ {
SSL_set_ex_data(_pSSL, SSLManager::instance().socketIndex(), nullptr);
SSL_free(_pSSL); SSL_free(_pSSL);
_pSSL = 0; _pSSL = 0;
} }
@ -623,20 +627,7 @@ void SecureSocketImpl::abort()
Session::Ptr SecureSocketImpl::currentSession() Session::Ptr SecureSocketImpl::currentSession()
{ {
if (_pSSL) return _pSession;
{
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;
} }
@ -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<SecureSocketImpl*>(pEx);
pThis->_pSession = new Session(pSession);
return 1;
}
else return 0;
}
} } // namespace Poco::Net } } // namespace Poco::Net

View File

@ -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 "Poco/Net/Session.h"
#include <openssl/ssl.h>
namespace Poco { 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 } } // namespace Poco::Net

View File

@ -370,15 +370,15 @@ void TCPServerTest::testReuseSession()
ss1.useSession(pSession); ss1.useSession(pSession);
ss1.connect(sa); ss1.connect(sa);
assertTrue (ss1.sessionWasReused());
assertTrue (ss1.currentSession() == pSession);
ss1.sendBytes(data.data(), (int) data.size()); ss1.sendBytes(data.data(), (int) data.size());
n = ss1.receiveBytes(buffer, sizeof(buffer)); n = ss1.receiveBytes(buffer, sizeof(buffer));
assertTrue (ss1.sessionWasReused());
assertTrue (n > 0); assertTrue (n > 0);
assertTrue (std::string(buffer, n) == data); assertTrue (std::string(buffer, n) == data);
assertTrue (srv.currentConnections() == 1); assertTrue (srv.currentConnections() == 1);
assertTrue (srv.queuedConnections() == 0); assertTrue (srv.queuedConnections() == 0);
assertTrue (srv.totalConnections() == 2); assertTrue (srv.totalConnections() == 2);
pSession = ss1.currentSession();
ss1.close(); ss1.close();
Thread::sleep(300); Thread::sleep(300);
assertTrue (srv.currentConnections() == 0); assertTrue (srv.currentConnections() == 0);
@ -388,10 +388,9 @@ void TCPServerTest::testReuseSession()
ss1.useSession(pSession); ss1.useSession(pSession);
ss1.connect(sa); ss1.connect(sa);
assertTrue (!ss1.sessionWasReused());
assertTrue (ss1.currentSession() != pSession);
ss1.sendBytes(data.data(), (int) data.size()); ss1.sendBytes(data.data(), (int) data.size());
n = ss1.receiveBytes(buffer, sizeof(buffer)); n = ss1.receiveBytes(buffer, sizeof(buffer));
assertTrue (!ss1.sessionWasReused());
assertTrue (n > 0); assertTrue (n > 0);
assertTrue (std::string(buffer, n) == data); assertTrue (std::string(buffer, n) == data);
assertTrue (srv.currentConnections() == 1); assertTrue (srv.currentConnections() == 1);