domain(NULL),
#if USE_OPENSSL
sslContext(NULL),
- sslSession(NULL),
#endif
front_end_https(0),
connection_auth(2 /* auto */)
#if USE_OPENSSL
if (sslContext)
SSL_CTX_free(sslContext);
-
- if (sslSession)
- SSL_SESSION_free(sslSession);
#endif
}
/// security settings for peer connection
Security::PeerOptions secure;
Security::ContextPtr sslContext;
-#if USE_OPENSSL
- SSL_SESSION *sslSession;
-#endif
+ Security::SessionStatePointer sslSession;
int front_end_https;
int connection_auth;
fs/libfs.la \
DiskIO/libdiskio.la \
comm/libcomm.la \
- $(SSL_LIBS) \
security/libsecurity.la \
+ $(SSL_LIBS) \
ipc/libipc.la \
mgr/libmgr.la \
anyp/libanyp.la \
Adaptation::Icap::ServiceRep::ServiceRep(const ServiceConfigPointer &svcCfg):
AsyncJob("Adaptation::Icap::ServiceRep"), Adaptation::Service(svcCfg),
sslContext(NULL),
-#if USE_OPENSSL
- sslSession(NULL),
-#endif
theOptions(NULL), theOptionsFetcher(0), theLastUpdate(0),
theBusyConns(0),
theAllWaiters(0),
virtual void noteAdaptationAnswer(const Answer &answer);
Security::ContextPtr sslContext;
-#if USE_OPENSSL
- SSL_SESSION *sslSession;
-#endif
+ Security::SessionStatePointer sslSession;
private:
// stores Prepare() callback info
if (!Security::PeerConnector::initialize(serverSession))
return false;
-#if USE_OPENSSL
assert(!icapService->cfg().secure.sslDomain.isEmpty());
+#if USE_OPENSSL
SBuf *host = new SBuf(icapService->cfg().secure.sslDomain);
SSL_set_ex_data(serverSession.get(), ssl_ex_index_server, host);
ACLFilledChecklist *check = static_cast<ACLFilledChecklist *>(SSL_get_ex_data(serverSession.get(), ssl_ex_index_cert_error_check));
if (check)
check->dst_peer_name = *host;
+#endif
- if (icapService->sslSession)
- SSL_set_session(serverSession.get(), icapService->sslSession);
-
+ Security::SetSessionResumeData(serverSession, icapService->sslSession);
return true;
-#else
- return false;
-#endif
}
void
if (error)
return;
-#if USE_OPENSSL
const int fd = serverConnection()->fd;
- auto ssl = fd_table[fd].ssl.get();
- assert(ssl);
- if (!SSL_session_reused(ssl)) {
- if (icapService->sslSession)
- SSL_SESSION_free(icapService->sslSession);
- icapService->sslSession = SSL_get1_session(ssl);
- }
-#endif
+ Security::MaybeGetSessionResumeData(fd_table[fd].ssl, icapService->sslSession);
}
void
return;
}
- if (SSL_session_reused(ssl)) {
+ if (Security::SessionIsResumed(fd_table[fd].ssl)) {
debugs(83, 2, "clientNegotiateSSL: Session " << SSL_get_session(ssl) <<
" reused on FD " << fd << " (" << fd_table[fd].ipaddr << ":" << (int)fd_table[fd].remote_port << ")");
} else {
SBuf *host = new SBuf(peer->secure.sslDomain);
SSL_set_ex_data(serverSession.get(), ssl_ex_index_server, host);
- if (peer->sslSession)
- SSL_set_session(serverSession.get(), peer->sslSession);
+ Security::SetSessionResumeData(serverSession, peer->sslSession);
} else {
SBuf *hostName = new SBuf(request->url.host());
SSL_set_ex_data(serverSession.get(), ssl_ex_index_server, (void*)hostName);
return;
}
-#if USE_OPENSSL
- const int fd = serverConnection()->fd;
- Security::SessionPtr ssl = fd_table[fd].ssl.get();
- if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
- if (serverConnection()->getPeer()->sslSession)
- SSL_SESSION_free(serverConnection()->getPeer()->sslSession);
-
- serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl);
+ if (auto *peer = serverConnection()->getPeer()) {
+ const int fd = serverConnection()->fd;
+ Security::MaybeGetSessionResumeData(fd_table[fd].ssl, peer->sslSession);
}
-#endif
}
* Please see the COPYING and CONTRIBUTORS files for details.
*/
+/* DEBUG: section 83 TLS session management */
+
#include "squid.h"
#include "anyp/PortCfg.h"
#include "base/RunnersRegistry.h"
+#include "Debug.h"
#include "ipc/MemMap.h"
#include "security/Session.h"
#include "SquidConfig.h"
#define SSL_SESSION_ID_SIZE 32
#define SSL_SESSION_MAX_SIZE 10*1024
+bool
+Security::SessionIsResumed(const Security::SessionPointer &s)
+{
+ bool result = false;
+#if USE_OPENSSL
+ result = SSL_session_reused(s.get()) == 1;
+#elif USE_GNUTLS
+ result = gnutls_session_is_resumed(s.get()) != 0;
+#endif
+ debugs(83, 7, "session=" << (void*)s.get() << ", query? answer: " << (result ? 'T' : 'F') );
+ return result;
+}
+
+void
+Security::MaybeGetSessionResumeData(const Security::SessionPointer &s, Security::SessionStatePointer &data)
+{
+ if (!SessionIsResumed(s)) {
+#if USE_OPENSSL
+ // nil is valid for SSL_get1_session(), it cannot fail.
+ data.reset(SSL_get1_session(s.get()));
+#elif USE_GNUTLS
+ gnutls_datum_t *tmp = nullptr;
+ const auto x = gnutls_session_get_data2(s.get(), tmp);
+ if (x != GNUTLS_E_SUCCESS) {
+ debugs(83, 3, "session=" << (void*)s.get() << " error: " << gnutls_strerror(x));
+ }
+ data.reset(tmp);
+#endif
+ debugs(83, 5, "session=" << (void*)s.get() << " data=" << (void*)data.get());
+ } else {
+ debugs(83, 5, "session=" << (void*)s.get() << " data=" << (void*)data.get() << ", do nothing.");
+ }
+}
+
+void
+Security::SetSessionResumeData(const Security::SessionPointer &s, const Security::SessionStatePointer &data)
+{
+ if (data) {
+#if USE_OPENSSL
+ if (!SSL_set_session(s.get(), data.get())) {
+ const auto ssl_error = ERR_get_error();
+ debugs(83, 3, "session=" << (void*)s.get() << " data=" << (void*)data.get() <<
+ " resume error: " << ERR_error_string(ssl_error, nullptr));
+ }
+#elif USE_GNUTLS
+ const auto x = gnutls_session_set_data(s.get(), data->data, data->size);
+ if (x != GNUTLS_E_SUCCESS) {
+ debugs(83, 3, "session=" << (void*)s.get() << " data=" << (void*)data.get() <<
+ " resume error: " << gnutls_strerror(x));
+ }
+#else
+ // critical because, how did it get here?
+ debugs(83, DBG_CRITICAL, "no TLS library. session=" << (void*)s.get() << " data=" << (void*)data.get());
+#endif
+ debugs(83, 5, "session=" << (void*)s.get() << " data=" << (void*)data.get());
+ } else {
+ debugs(83, 5, "session=" << (void*)s.get() << " no resume data");
+ }
+}
+
static bool
isTlsServer()
{
#ifndef SQUID_SRC_SECURITY_SESSION_H
#define SQUID_SRC_SECURITY_SESSION_H
+#include "base/HardFun.h"
#include "security/LockingPointer.h"
#include <memory>
CtoCpp1(SSL_free, SSL *);
typedef LockingPointer<SSL, Security::SSL_free_cpp, CRYPTO_LOCK_SSL> SessionPointer;
+typedef std::unique_ptr<SSL_SESSION, HardFun<void, SSL_SESSION*, &SSL_SESSION_free>> SessionStatePointer;
+
#elif USE_GNUTLS
typedef gnutls_session_t SessionPtr;
// Locks can be implemented attaching locks counter to gnutls_session_t
CtoCpp1(gnutls_deinit, gnutls_session_t);
typedef LockingPointer<struct gnutls_session_int, gnutls_deinit_cpp, -1> SessionPointer;
+// wrapper function to get around gnutls_free being a typedef
+inline void squid_gnutls_free(void *d) {gnutls_free(d);}
+typedef std::unique_ptr<gnutls_datum_t, HardFun<void, void*, &Security::squid_gnutls_free>> SessionStatePointer;
+
#else
// use void* so we can check against NULL
typedef void* SessionPtr;
CtoCpp1(xfree, SessionPtr);
typedef LockingPointer<void, xfree_cpp, -1> SessionPointer;
+typedef std::unique_ptr<int> SessionStatePointer;
+
#endif
+/// whether the session is a resumed one
+bool SessionIsResumed(const Security::SessionPointer &);
+
+/**
+ * When the session is not a resumed session, retrieve the details needed to
+ * resume a later connection and store them in 'data'. This may result in 'data'
+ * becoming a nil Pointer if no details exist or an error occurs.
+ *
+ * When the session is already a resumed session, do nothing and leave 'data'
+ * unhanged.
+ * XXX: is this latter behaviour always correct?
+ */
+void MaybeGetSessionResumeData(const Security::SessionPointer &, Security::SessionStatePointer &data);
+
+/// Set the data for resuming a previous session.
+/// Needs to be done before using the SessionPointer for a handshake.
+void SetSessionResumeData(const Security::SessionPointer &, const Security::SessionStatePointer &);
+
} // namespace Security
#endif /* SQUID_SRC_SECURITY_SESSION_H */
bool Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &) STUB_RETVAL(false)
void Security::ServerOptions::updateContextEecdh(Security::ContextPtr &) STUB
+#include "security/Session.h"
+namespace Security {
+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
+} // namespace Security
+