Commit 94ed107a authored by Andrew Huang's avatar Andrew Huang Committed by Facebook GitHub Bot

Forward newly negotiated sessions to corresponding SSLSession

Summary:
When a session is newly negotiated, pass it to the SSLSession belonging to the corresponding AsyncSSLSocket through SSLSessionManager. That SSLSession then becomes resumable.

This allows SSLSessions obtained from an AsyncSSLSocket to later become resumable once the session is negotiated (asynchronously in TLS 1.3).

Reviewed By: yfeldblum

Differential Revision: D21035731

fbshipit-source-id: acbaa258798e7774e742c5765ef33e24573f1c78
parent 0ad1b3bb
...@@ -833,6 +833,7 @@ void AsyncSSLSocket::sslConn( ...@@ -833,6 +833,7 @@ void AsyncSSLSocket::sslConn(
#endif #endif
SSL_set_ex_data(ssl_.get(), getSSLExDataIndex(), this); SSL_set_ex_data(ssl_.get(), getSSLExDataIndex(), this);
sslSessionManager_.attachToSSL(ssl_.get());
handshakeConnectTimeout_ = timeout; handshakeConnectTimeout_ = timeout;
startSSLConnect(); startSSLConnect();
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <folly/SharedMutex.h> #include <folly/SharedMutex.h>
#include <folly/SpinLock.h> #include <folly/SpinLock.h>
#include <folly/ssl/Init.h> #include <folly/ssl/Init.h>
#include <folly/ssl/SSLSessionManager.h>
#include <folly/system/ThreadId.h> #include <folly/system/ThreadId.h>
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
...@@ -38,6 +39,7 @@ int getExDataIndex() { ...@@ -38,6 +39,7 @@ int getExDataIndex() {
} // namespace } // namespace
namespace folly { namespace folly {
// //
// For OpenSSL portability API // For OpenSSL portability API
...@@ -709,7 +711,14 @@ int SSLContext::newSessionCallback(SSL* ssl, SSL_SESSION* session) { ...@@ -709,7 +711,14 @@ int SSLContext::newSessionCallback(SSL* ssl, SSL_SESSION* session) {
cb->onNewSession(ssl, std::move(sessionPtr)); cb->onNewSession(ssl, std::move(sessionPtr));
} }
SSL_SESSION_free(session); // Session will either be moved to session manager or
// freed when the unique_ptr goes out of scope
auto sessionPtr = folly::ssl::SSLSessionUniquePtr(session);
auto sessionManager = folly::ssl::SSLSessionManager::getFromSSL(ssl);
if (sessionManager) {
sessionManager->onNewSession(std::move(sessionPtr));
}
return 1; return 1;
} }
......
...@@ -30,21 +30,6 @@ using folly::ssl::detail::OpenSSLSession; ...@@ -30,21 +30,6 @@ using folly::ssl::detail::OpenSSLSession;
namespace folly { namespace folly {
class SimpleCallbackManager
: public folly::SSLContext::SessionLifecycleCallbacks {
public:
void onNewSession(SSL* ssl, folly::ssl::SSLSessionUniquePtr session)
override {
auto socket = folly::AsyncSSLSocket::getFromSSL(ssl);
auto sslSession =
std::dynamic_pointer_cast<folly::ssl::detail::OpenSSLSession>(
socket->getSSLSessionV2());
if (sslSession) {
sslSession->setActiveSession(std::move(session));
}
}
};
void getfds(NetworkSocket fds[2]) { void getfds(NetworkSocket fds[2]) {
if (netops::socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) { if (netops::socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) {
FAIL() << "failed to create socketpair: " << errnoStr(errno); FAIL() << "failed to create socketpair: " << errnoStr(errno);
...@@ -62,12 +47,12 @@ void getctx( ...@@ -62,12 +47,12 @@ void getctx(
std::shared_ptr<folly::SSLContext> serverCtx) { std::shared_ptr<folly::SSLContext> serverCtx) {
clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
clientCtx->loadTrustedCertificates(kTestCA); clientCtx->loadTrustedCertificates(kTestCA);
clientCtx->setSessionLifecycleCallbacks( clientCtx->enableTLS13();
std::make_unique<SimpleCallbackManager>());
serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
serverCtx->loadCertificate(kTestCert); serverCtx->loadCertificate(kTestCert);
serverCtx->loadPrivateKey(kTestKey); serverCtx->loadPrivateKey(kTestKey);
serverCtx->enableTLS13();
} }
class SSLSessionTest : public testing::Test { class SSLSessionTest : public testing::Test {
...@@ -98,9 +83,19 @@ TEST_F(SSLSessionTest, BasicTest) { ...@@ -98,9 +83,19 @@ TEST_F(SSLSessionTest, BasicTest) {
{ {
NetworkSocket fds[2]; NetworkSocket fds[2];
getfds(fds); getfds(fds);
AsyncSSLSocket::UniquePtr clientSock( AsyncSSLSocket::UniquePtr clientSock(
new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName)); new AsyncSSLSocket(clientCtx, &eventBase, fds[0], serverName));
auto clientPtr = clientSock.get(); auto clientPtr = clientSock.get();
sslSession = clientPtr->getSSLSessionV2();
ASSERT_NE(sslSession, nullptr);
{
auto opensslSession =
std::dynamic_pointer_cast<OpenSSLSession>(sslSession);
auto sessionPtr = opensslSession->getActiveSession();
ASSERT_EQ(sessionPtr.get(), nullptr);
}
AsyncSSLSocket::UniquePtr serverSock( AsyncSSLSocket::UniquePtr serverSock(
new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true)); new AsyncSSLSocket(dfServerCtx, &eventBase, fds[1], true));
SSLHandshakeClient client(std::move(clientSock), false, false); SSLHandshakeClient client(std::move(clientSock), false, false);
...@@ -110,16 +105,12 @@ TEST_F(SSLSessionTest, BasicTest) { ...@@ -110,16 +105,12 @@ TEST_F(SSLSessionTest, BasicTest) {
eventBase.loop(); eventBase.loop();
ASSERT_TRUE(client.handshakeSuccess_); ASSERT_TRUE(client.handshakeSuccess_);
ASSERT_FALSE(clientPtr->getSSLSessionReused()); ASSERT_FALSE(clientPtr->getSSLSessionReused());
{
sslSession = clientPtr->getSSLSessionV2(); auto opensslSession =
ASSERT_NE(sslSession, nullptr); std::dynamic_pointer_cast<OpenSSLSession>(sslSession);
auto sessionPtr = opensslSession->getActiveSession();
// The underlying SSL_SESSION is set in the session callback ASSERT_NE(sessionPtr.get(), nullptr);
// that is attached to the SSL_CTX. The session is guaranteed to }
// be resumable here in TLS 1.2, but not in TLS 1.3
auto opensslSession = std::dynamic_pointer_cast<OpenSSLSession>(sslSession);
auto sessionPtr = opensslSession->getActiveSession();
ASSERT_NE(sessionPtr.get(), nullptr);
} }
// Session resumption // Session resumption
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include <folly/ssl/SSLSessionManager.h> #include <folly/ssl/SSLSessionManager.h>
#include <folly/portability/OpenSSL.h>
#include <folly/ssl/OpenSSLPtrTypes.h> #include <folly/ssl/OpenSSLPtrTypes.h>
#include <folly/ssl/detail/OpenSSLSession.h> #include <folly/ssl/detail/OpenSSLSession.h>
...@@ -61,6 +62,29 @@ class SSLSessionRetrievalVisitor ...@@ -61,6 +62,29 @@ class SSLSessionRetrievalVisitor
} }
}; };
class SessionForwarderVisitor : boost::static_visitor<> {
public:
explicit SessionForwarderVisitor(SSLSessionUniquePtr sessionArg)
: sessionArg_{std::move(sessionArg)} {}
void operator()(const SSLSessionUniquePtr&) {}
void operator()(const std::shared_ptr<OpenSSLSession>& session) {
if (session) {
session->setActiveSession(std::move(sessionArg_));
}
}
private:
SSLSessionUniquePtr sessionArg_{nullptr};
};
int getSSLExDataIndex() {
static auto index =
SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
return index;
}
} // namespace } // namespace
namespace folly { namespace folly {
...@@ -96,5 +120,19 @@ shared_ptr<SSLSession> SSLSessionManager::getSession() const { ...@@ -96,5 +120,19 @@ shared_ptr<SSLSession> SSLSessionManager::getSession() const {
return boost::apply_visitor(visitor, session_); return boost::apply_visitor(visitor, session_);
} }
void SSLSessionManager::attachToSSL(SSL* ssl) {
SSL_set_ex_data(ssl, getSSLExDataIndex(), this);
}
SSLSessionManager* SSLSessionManager::getFromSSL(const SSL* ssl) {
return static_cast<SSLSessionManager*>(
SSL_get_ex_data(ssl, getSSLExDataIndex()));
}
void SSLSessionManager::onNewSession(SSLSessionUniquePtr session) {
auto visitor = SessionForwarderVisitor(std::move(session));
boost::apply_visitor(visitor, session_);
}
} // namespace ssl } // namespace ssl
} // namespace folly } // namespace folly
...@@ -17,10 +17,14 @@ ...@@ -17,10 +17,14 @@
#pragma once #pragma once
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include <folly/portability/OpenSSL.h>
#include <folly/ssl/OpenSSLPtrTypes.h> #include <folly/ssl/OpenSSLPtrTypes.h>
#include <folly/ssl/SSLSession.h> #include <folly/ssl/SSLSession.h>
namespace folly { namespace folly {
class SSLContext;
namespace ssl { namespace ssl {
namespace detail { namespace detail {
...@@ -51,9 +55,32 @@ class SSLSessionManager { ...@@ -51,9 +55,32 @@ class SSLSessionManager {
folly::ssl::SSLSessionUniquePtr getRawSession() const; folly::ssl::SSLSessionUniquePtr getRawSession() const;
/**
* Add SSLSessionManager instance to the ex data of ssl.
* Needs to be called for SSLSessionManager::getFromSSL to return
* a non-null pointer.
*/
void attachToSSL(SSL* ssl);
/**
* Get pointer to a SSLSessionManager instance that was added to
* the ex data of ssl through attachToSSL()
*/
static SSLSessionManager* getFromSSL(const SSL* ssl);
private: private:
// The SSL session. Which type the variant contains depends on the friend class folly::SSLContext;
// session API that is used.
/**
* Called by SSLContext when a new session is negotiated for the
* SSL connection that SSLSessionManager is attached to.
*/
void onNewSession(folly::ssl::SSLSessionUniquePtr session);
/**
* The SSL session. Which type the variant contains depends on the
* session API that is used.
*/
boost::variant< boost::variant<
folly::ssl::SSLSessionUniquePtr, folly::ssl::SSLSessionUniquePtr,
std::shared_ptr<folly::ssl::detail::OpenSSLSession>> std::shared_ptr<folly::ssl::detail::OpenSSLSession>>
......
...@@ -64,4 +64,20 @@ TEST(SSLSessionManagerTest, SetRawSesionTest) { ...@@ -64,4 +64,20 @@ TEST(SSLSessionManagerTest, SetRawSesionTest) {
EXPECT_EQ(nullptr, manager.getRawSession().get()); EXPECT_EQ(nullptr, manager.getRawSession().get());
} }
TEST(SSLSessionManagerTest, GetFromSSLTest) {
SSLSessionManager manager;
SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
SSL* ssl1 = SSL_new(ctx);
EXPECT_EQ(nullptr, SSLSessionManager::getFromSSL(ssl1));
SSL_free(ssl1);
SSL* ssl2 = SSL_new(ctx);
manager.attachToSSL(ssl2);
EXPECT_EQ(&manager, SSLSessionManager::getFromSSL(ssl2));
SSL_free(ssl2);
SSL_CTX_free(ctx);
}
} // namespace folly } // namespace folly
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment