]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
TLS: Move the remaining SSL_SESSION cache callbacks to security/Session.*.
authorAmos Jeffries <squid3@treenet.co.nz>
Tue, 20 Jun 2017 19:00:03 +0000 (07:00 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Tue, 20 Jun 2017 19:00:03 +0000 (07:00 +1200)
No GnuTLS additions here, or significant code changes. Most of this is a
straight cut-n-paste. Though it does make the slot lookup to auto in the
if-condition to simplify the callback code and removes some no longer
necessary comments as requested in audit.

src/security/Session.cc
src/security/Session.h
src/ssl/support.cc
src/ssl/support.h
src/tests/stub_libsecurity.cc

index b34bdc2961adb8fc03863454761e0f5ee3424734..9d33d2d7a029327fcc1356f360c9de3c25e58f41 100644 (file)
 #define SSL_SESSION_ID_SIZE 32
 #define SSL_SESSION_MAX_SIZE 10*1024
 
+#if USE_OPENSSL
+static Ipc::MemMap *SessionCache = nullptr;
+static const char *SessionCacheName = "tls_session_cache";
+#endif
+
 #if USE_OPENSSL || USE_GNUTLS
 static int
 tls_read_method(int fd, char *buf, int len)
@@ -274,6 +279,113 @@ isTlsServer()
     return false;
 }
 
+#if USE_OPENSSL
+static int
+store_session_cb(SSL *ssl, SSL_SESSION *session)
+{
+    if (!SessionCache)
+        return 0;
+
+    debugs(83, 5, "Request to store SSL_SESSION");
+
+    SSL_SESSION_set_timeout(session, Config.SSL.session_ttl);
+
+#if HAVE_LIBSSL_SSL_SESSION_GET_ID
+    unsigned int idlen;
+    const unsigned char *id = SSL_SESSION_get_id(session, &idlen);
+#else
+    unsigned char *id = session->session_id;
+    unsigned int idlen = session->session_id_length;
+#endif
+    // XXX: the other calls [to openForReading()] do not copy the sessionId to a char buffer, does this really have to?
+    unsigned char key[MEMMAP_SLOT_KEY_SIZE];
+    // Session ids are of size 32bytes. They should always fit to a
+    // MemMap::Slot::key
+    assert(idlen <= MEMMAP_SLOT_KEY_SIZE);
+    memset(key, 0, sizeof(key));
+    memcpy(key, id, idlen);
+    int pos;
+    if (auto slotW = SessionCache->openForWriting(static_cast<const cache_key*>(key), pos)) {
+        int lenRequired = i2d_SSL_SESSION(session, nullptr);
+        if (lenRequired <  MEMMAP_SLOT_DATA_SIZE) {
+            unsigned char *p = static_cast<unsigned char *>(slotW->p);
+            lenRequired = i2d_SSL_SESSION(session, &p);
+            slotW->set(key, nullptr, lenRequired, squid_curtime + Config.SSL.session_ttl);
+        }
+        SessionCache->closeForWriting(pos);
+        debugs(83, 5, "wrote an SSL_SESSION entry of size " << lenRequired << " at pos " << pos);
+    }
+    return 0;
+}
+
+static void
+remove_session_cb(SSL_CTX *, SSL_SESSION *sessionID)
+{
+    if (!SessionCache)
+        return;
+
+    debugs(83, 5, "Request to remove corrupted or not valid SSL_SESSION");
+    int pos;
+    if (SessionCache->openForReading(reinterpret_cast<const cache_key*>(sessionID), pos)) {
+        SessionCache->closeForReading(pos);
+        // TODO:
+        // What if we are not able to remove the session?
+        // Maybe schedule a job to remove it later?
+        // For now we just have an invalid entry in cache until will be expired
+        // The OpenSSL library will reject it when we try to use it
+        SessionCache->free(pos);
+    }
+}
+
+static SSL_SESSION *
+#if SQUID_USE_CONST_SSL_SESSION_CBID
+get_session_cb(SSL *, const unsigned char *sessionID, int len, int *copy)
+#else
+get_session_cb(SSL *, unsigned char *sessionID, int len, int *copy)
+#endif
+{
+    if (!SessionCache)
+        return nullptr;
+
+    const unsigned int *p = reinterpret_cast<const unsigned int *>(sessionID);
+    debugs(83, 5, "Request to search for SSL_SESSION of len: " <<
+           len << p[0] << ":" << p[1]);
+
+    SSL_SESSION *session = nullptr;
+    int pos;
+    if (const auto slot = SessionCache->openForReading(static_cast<const cache_key*>(sessionID), pos)) {
+        if (slot->expire > squid_curtime) {
+            const unsigned char *ptr = slot->p;
+            session = d2i_SSL_SESSION(nullptr, &ptr, slot->pSize);
+            debugs(83, 5, "SSL_SESSION retrieved from cache at pos " << pos);
+        } else
+            debugs(83, 5, "SSL_SESSION in cache expired");
+        SessionCache->closeForReading(pos);
+    }
+
+    if (!session)
+        debugs(83, 5, "Failed to retrieve SSL_SESSION from cache\n");
+
+    // With the parameter copy the callback can require the SSL engine
+    // to increment the reference count of the SSL_SESSION object, Normally
+    // the reference count is not incremented and therefore the session must
+    // not be explicitly freed with SSL_SESSION_free(3).
+    *copy = 0;
+    return session;
+}
+
+void
+Security::SetSessionCacheCallbacks(Security::ContextPointer &ctx)
+{
+    if (SessionCache) {
+        SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL);
+        SSL_CTX_sess_set_new_cb(ctx.get(), store_session_cb);
+        SSL_CTX_sess_set_remove_cb(ctx.get(), remove_session_cb);
+        SSL_CTX_sess_set_get_cb(ctx.get(), get_session_cb);
+    }
+}
+#endif /* USE_OPENSSL */
+
 void
 initializeSessionCache()
 {
@@ -285,15 +397,15 @@ initializeSessionCache()
 
     int configuredItems = ::Config.SSL.sessionCacheSize / sizeof(Ipc::MemMap::Slot);
     if (IamWorkerProcess() && configuredItems)
-        Ssl::SessionCache = new Ipc::MemMap(Ssl::SessionCacheName);
+        SessionCache = new Ipc::MemMap(SessionCacheName);
     else {
-        Ssl::SessionCache = nullptr;
+        SessionCache = nullptr;
         return;
     }
 
     for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
         if (s->secure.staticContext)
-            Ssl::SetSessionCallbacks(s->secure.staticContext);
+            Security::SetSessionCacheCallbacks(s->secure.staticContext);
     }
 #endif
 }
@@ -319,8 +431,8 @@ RunnerRegistrationEntry(SharedSessionCacheRr);
 void
 SharedSessionCacheRr::useConfig()
 {
-#if USE_OPENSSL // while Ssl:: bits in use
-    if (Ssl::SessionCache || !isTlsServer()) //no need to configure ssl session cache.
+#if USE_OPENSSL
+    if (SessionCache || !isTlsServer()) // no need to configure SSL_SESSION* cache.
         return;
 
     Ipc::Mem::RegisteredRunner::useConfig();
@@ -331,19 +443,19 @@ SharedSessionCacheRr::useConfig()
 void
 SharedSessionCacheRr::create()
 {
-    if (!isTlsServer()) //no need to configure ssl session cache.
+    if (!isTlsServer()) // no need to configure SSL_SESSION* cache.
         return;
 
-#if USE_OPENSSL // while Ssl:: bits in use
+#if USE_OPENSSL
     if (int items = Config.SSL.sessionCacheSize / sizeof(Ipc::MemMap::Slot))
-        owner = Ipc::MemMap::Init(Ssl::SessionCacheName, items);
+        owner = Ipc::MemMap::Init(SessionCacheName, items);
 #endif
 }
 
 SharedSessionCacheRr::~SharedSessionCacheRr()
 {
     // XXX: Enable after testing to reduce at-exit memory "leaks".
-    // delete Ssl::SessionCache;
+    // delete SessionCache;
 
     delete owner;
 }
index 6551bed601953333f5690d01c649a9c9e0228c00..37f3e7ca52c303fa6f6e9b08fb3404a143b76ff8 100644 (file)
@@ -78,6 +78,10 @@ void MaybeGetSessionResumeData(const Security::SessionPointer &, Security::Sessi
 void SetSessionResumeData(const Security::SessionPointer &, const Security::SessionStatePointer &);
 
 #if USE_OPENSSL
+// TODO: remove from public API. It is only public because of configureSslContext() in ssl/support.cc
+/// Setup the given TLS context with callbacks used to manage the session cache
+void SetSessionCacheCallbacks(Security::ContextPointer &);
+
 /// Helper function to retrieve a (non-locked) ContextPointer from a SessionPointer
 inline Security::ContextPointer
 GetFrom(Security::SessionPointer &s)
index 40b92caf8e09c92c08a98da8dc5d0c115d71f309..f5705f96de2d4ff868162a4bf562df742be9f2bd 100644 (file)
@@ -38,9 +38,6 @@
 // TODO: Move ssl_ex_index_* global variables from global.cc here.
 int ssl_ex_index_ssl_untrusted_chain = -1;
 
-Ipc::MemMap *Ssl::SessionCache = NULL;
-const char *Ssl::SessionCacheName = "ssl_session_cache";
-
 static Ssl::CertsIndexedList SquidUntrustedCerts;
 
 const EVP_MD *Ssl::DefaultSignHash = NULL;
@@ -564,7 +561,7 @@ configureSslContext(Security::ContextPointer &ctx, AnyP::PortCfg &port)
     if (port.secure.parsedFlags & SSL_FLAG_DONT_VERIFY_DOMAIN)
         SSL_CTX_set_ex_data(ctx.get(), ssl_ctx_ex_index_dont_verify_domain, (void *) -1);
 
-    Ssl::SetSessionCallbacks(ctx);
+    Security::SetSessionCacheCallbacks(ctx);
 
     return true;
 }
@@ -1381,113 +1378,5 @@ bool Ssl::generateUntrustedCert(Security::CertPointer &untrustedCert, EVP_PKEY_P
     return Ssl::generateSslCertificate(untrustedCert, untrustedPkey, certProperties);
 }
 
-static int
-store_session_cb(SSL *ssl, SSL_SESSION *session)
-{
-    if (!Ssl::SessionCache)
-        return 0;
-
-    debugs(83, 5, "Request to store SSL Session ");
-
-    SSL_SESSION_set_timeout(session, Config.SSL.session_ttl);
-
-#if HAVE_LIBSSL_SSL_SESSION_GET_ID
-    unsigned int idlen;
-    const unsigned char *id = SSL_SESSION_get_id(session, &idlen);
-#else
-    unsigned char *id = session->session_id;
-    unsigned int idlen = session->session_id_length;
-#endif
-    unsigned char key[MEMMAP_SLOT_KEY_SIZE];
-    // Session ids are of size 32bytes. They should always fit to a
-    // MemMap::Slot::key
-    assert(idlen <= MEMMAP_SLOT_KEY_SIZE);
-    memset(key, 0, sizeof(key));
-    memcpy(key, id, idlen);
-    int pos;
-    Ipc::MemMap::Slot *slotW = Ssl::SessionCache->openForWriting((const cache_key*)key, pos);
-    if (slotW) {
-        int lenRequired =  i2d_SSL_SESSION(session, NULL);
-        if (lenRequired <  MEMMAP_SLOT_DATA_SIZE) {
-            unsigned char *p = (unsigned char *)slotW->p;
-            lenRequired = i2d_SSL_SESSION(session, &p);
-            slotW->set(key, NULL, lenRequired, squid_curtime + Config.SSL.session_ttl);
-        }
-        Ssl::SessionCache->closeForWriting(pos);
-        debugs(83, 5, "wrote an ssl session entry of size " << lenRequired << " at pos " << pos);
-    }
-    return 0;
-}
-
-static void
-remove_session_cb(SSL_CTX *, SSL_SESSION *sessionID)
-{
-    if (!Ssl::SessionCache)
-        return ;
-
-    debugs(83, 5, "Request to remove corrupted or not valid SSL Session ");
-    int pos;
-    Ipc::MemMap::Slot const *slot = Ssl::SessionCache->openForReading((const cache_key*)sessionID, pos);
-    if (slot == NULL)
-        return;
-    Ssl::SessionCache->closeForReading(pos);
-    // TODO:
-    // What if we are not able to remove the session?
-    // Maybe schedule a job to remove it later?
-    // For now we just have an invalid entry in cache until will be expired
-    // The openSSL will reject it when we try to use it
-    Ssl::SessionCache->free(pos);
-}
-
-static SSL_SESSION *
-#if SQUID_USE_CONST_SSL_SESSION_CBID
-get_session_cb(SSL *, const unsigned char *sessionID, int len, int *copy)
-#else
-get_session_cb(SSL *, unsigned char *sessionID, int len, int *copy)
-#endif
-{
-    if (!Ssl::SessionCache)
-        return NULL;
-
-    SSL_SESSION *session = NULL;
-    const unsigned int *p;
-    p = (unsigned int *)sessionID;
-    debugs(83, 5, "Request to search for SSL Session of len:" <<
-           len << p[0] << ":" << p[1]);
-
-    int pos;
-    Ipc::MemMap::Slot const *slot = Ssl::SessionCache->openForReading((const cache_key*)sessionID, pos);
-    if (slot != NULL) {
-        if (slot->expire > squid_curtime) {
-            const unsigned char *ptr = slot->p;
-            session = d2i_SSL_SESSION(NULL, &ptr, slot->pSize);
-            debugs(83, 5, "Session retrieved from cache at pos " << pos);
-        } else
-            debugs(83, 5, "Session in cache expired");
-        Ssl::SessionCache->closeForReading(pos);
-    }
-
-    if (!session)
-        debugs(83, 5, "Failed to retrieved from cache\n");
-
-    // With the parameter copy the callback can require the SSL engine
-    // to increment the reference count of the SSL_SESSION object, Normally
-    // the reference count is not incremented and therefore the session must
-    // not be explicitly freed with SSL_SESSION_free(3).
-    *copy = 0;
-    return session;
-}
-
-void
-Ssl::SetSessionCallbacks(Security::ContextPointer &ctx)
-{
-    if (Ssl::SessionCache) {
-        SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL);
-        SSL_CTX_sess_set_new_cb(ctx.get(), store_session_cb);
-        SSL_CTX_sess_set_remove_cb(ctx.get(), remove_session_cb);
-        SSL_CTX_sess_set_get_cb(ctx.get(), get_session_cb);
-    }
-}
-
 #endif /* USE_OPENSSL */
 
index a940e5915675af9088aed43a16f18cde9a4f981e..0537a2789f002939758bb8c2f8bccdee1a927871 100644 (file)
@@ -73,10 +73,6 @@ class ErrorDetail;
 class CertValidationResponse;
 typedef RefCount<CertValidationResponse> CertValidationResponsePointer;
 
-void SetSessionCallbacks(Security::ContextPointer &);
-extern Ipc::MemMap *SessionCache;
-extern const char *SessionCacheName;
-
 /// initialize a TLS server context with OpenSSL specific settings
 bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &);
 
index 835c8cdc38e24045e330abcc787a361804c7a08f..055dcec7e351e9f247a44b6ffe04660750141ba7 100644 (file)
@@ -102,6 +102,7 @@ bool SessionIsResumed(const Security::SessionPointer &) STUB_RETVAL(false)
 void MaybeGetSessionResumeData(const Security::SessionPointer &, Security::SessionStatePointer &) STUB
 void SetSessionResumeData(const Security::SessionPointer &, const Security::SessionStatePointer &) STUB
 #if USE_OPENSSL
+void SetSessionCacheCallbacks(Security::ContextPointer &) STUB
 Security::SessionPointer NewSessionObject(const Security::ContextPointer &) STUB_RETVAL(nullptr)
 #endif
 } // namespace Security