|
@@ -53,11 +53,13 @@ CAsyncSslSocketLayer::CAsyncSslSocketLayer()
|
|
|
m_onCloseCalled = false;
|
|
|
m_Main = NULL;
|
|
|
m_sessionid = NULL;
|
|
|
+ m_sessionidSerialized = NULL;
|
|
|
m_sessionreuse = true;
|
|
|
m_sessionreuse_failed = false;
|
|
|
|
|
|
FCertificate = NULL;
|
|
|
FPrivateKey = NULL;
|
|
|
+ m_CriticalSection.reset(new TCriticalSection());
|
|
|
}
|
|
|
|
|
|
CAsyncSslSocketLayer::~CAsyncSslSocketLayer()
|
|
@@ -627,6 +629,28 @@ BOOL CAsyncSslSocketLayer::Connect(LPCTSTR lpszHostAddress, UINT nHostPort)
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
+void CAsyncSslSocketLayer::SetSession(SSL_SESSION * Session)
|
|
|
+{
|
|
|
+ TGuard Guard(m_CriticalSection.get());
|
|
|
+ if (m_sessionid != NULL)
|
|
|
+ {
|
|
|
+ SSL_SESSION_free(m_sessionid);
|
|
|
+ }
|
|
|
+ if (m_sessionidSerialized != NULL)
|
|
|
+ {
|
|
|
+ delete[] m_sessionidSerialized;
|
|
|
+ m_sessionidSerialized = NULL;
|
|
|
+ }
|
|
|
+ m_sessionid = Session;
|
|
|
+ if (m_sessionid != NULL)
|
|
|
+ {
|
|
|
+ m_sessionidSerializedLen = i2d_SSL_SESSION(m_sessionid, NULL);
|
|
|
+ m_sessionidSerialized = new unsigned char[m_sessionidSerializedLen];
|
|
|
+ unsigned char * P = m_sessionidSerialized;
|
|
|
+ i2d_SSL_SESSION(m_sessionid, &P);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
bool CAsyncSslSocketLayer::HandleSession(SSL_SESSION * Session)
|
|
|
{
|
|
|
bool Result = false;
|
|
@@ -648,30 +672,22 @@ bool CAsyncSslSocketLayer::HandleSession(SSL_SESSION * Session)
|
|
|
m_Main->m_sessionreuse_failed = true;
|
|
|
}
|
|
|
}
|
|
|
- LogSocketMessageRaw(FZ_LOG_DEBUG, L"Saving session ID");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- SSL_SESSION_free(m_sessionid);
|
|
|
LogSocketMessageRaw(FZ_LOG_INFO, L"Session ID changed");
|
|
|
}
|
|
|
- m_sessionid = Session;
|
|
|
- // Some TLS 1.3 servers require reuse of the session of the previous data connection, not of the main session.
|
|
|
- // It seems that it's safe to do this even for older TLS versions, but let's not for now.
|
|
|
- // Once we do, we can simply always use main session's m_sessionid field in the code above.
|
|
|
- if ((SSL_version(m_ssl) >= TLS1_3_VERSION) && (m_Main != NULL))
|
|
|
+
|
|
|
+ if (m_Main == NULL)
|
|
|
+ {
|
|
|
+ LogSocketMessageRaw(FZ_LOG_INFO, L"Saving session ID");
|
|
|
+ SetSession(Session);
|
|
|
+ Result = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- if (m_Main->m_sessionid != NULL)
|
|
|
- {
|
|
|
- SSL_SESSION_free(m_Main->m_sessionid);
|
|
|
- }
|
|
|
- m_Main->m_sessionid = Session;
|
|
|
- if (Session != NULL)
|
|
|
- {
|
|
|
- SSL_SESSION_up_ref(Session);
|
|
|
- }
|
|
|
+ m_sessionid = Session;
|
|
|
}
|
|
|
- Result = true;
|
|
|
}
|
|
|
}
|
|
|
return Result;
|
|
@@ -814,14 +830,22 @@ int CAsyncSslSocketLayer::InitSSLConnection(bool clientMode,
|
|
|
m_sessionreuse = sessionreuse;
|
|
|
if ((m_Main != NULL) && m_sessionreuse)
|
|
|
{
|
|
|
- if (m_Main->m_sessionid == NULL)
|
|
|
+ TGuard Guard(m_Main->m_CriticalSection.get());
|
|
|
+ if (m_Main->m_sessionidSerialized == NULL)
|
|
|
{
|
|
|
DebugFail();
|
|
|
SSL_set_session(m_ssl, NULL);
|
|
|
}
|
|
|
else if (!m_Main->m_sessionreuse_failed)
|
|
|
{
|
|
|
- if (!SSL_set_session(m_ssl, m_Main->m_sessionid))
|
|
|
+ // This is what Python SSL module does, instead of directly using SSL_SESSION of the other session,
|
|
|
+ // claiming a bug in OpenSSL 1.1.1 and newer. See PySSL_get_session/PySSL_set_session.
|
|
|
+ // OpenSSL refutes this as a bug in Python session handling.
|
|
|
+ // https://github.com/openssl/openssl/issues/1550
|
|
|
+ // But it works for us too.
|
|
|
+ const unsigned char * P = m_Main->m_sessionidSerialized;
|
|
|
+ SSL_SESSION * Session = DebugNotNull(d2i_SSL_SESSION(NULL, &P, m_Main->m_sessionidSerializedLen));
|
|
|
+ if (!SSL_set_session(m_ssl, Session))
|
|
|
{
|
|
|
LogSocketMessageRaw(FZ_LOG_INFO, L"SSL_set_session failed");
|
|
|
return SSL_FAILURE_INITSSL;
|
|
@@ -943,11 +967,7 @@ void CAsyncSslSocketLayer::ResetSslSession()
|
|
|
cur = cur->pNext;
|
|
|
}
|
|
|
|
|
|
- if (m_sessionid != NULL)
|
|
|
- {
|
|
|
- SSL_SESSION_free(m_sessionid);
|
|
|
- m_sessionid = NULL;
|
|
|
- }
|
|
|
+ SetSession(NULL);
|
|
|
m_sessionreuse = true;
|
|
|
m_sessionreuse_failed = false;
|
|
|
|
|
@@ -1195,13 +1215,11 @@ void CAsyncSslSocketLayer::apps_ssl_info_callback(const SSL *s, int where, int r
|
|
|
{
|
|
|
// For 1.2 and older, session is always established at this point.
|
|
|
// For 1.3, session can be restarted later, so this is handled in NewSessionCallback.
|
|
|
- if (SSL_version(pLayer->m_ssl) < TLS1_3_VERSION)
|
|
|
+ // But at least with Cerberus server, it is not, so if we want to have "reuse" logged, we need to do it here.
|
|
|
+ SSL_SESSION * sessionid = SSL_get1_session(pLayer->m_ssl);
|
|
|
+ if (!pLayer->HandleSession(sessionid))
|
|
|
{
|
|
|
- SSL_SESSION * sessionid = SSL_get1_session(pLayer->m_ssl);
|
|
|
- if (!pLayer->HandleSession(sessionid))
|
|
|
- {
|
|
|
- SSL_SESSION_free(sessionid);
|
|
|
- }
|
|
|
+ SSL_SESSION_free(sessionid);
|
|
|
}
|
|
|
int error = SSL_get_verify_result(pLayer->m_ssl);
|
|
|
pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERIFY_CERT, error);
|