]> git.ipfire.org Git - thirdparty/squid.git/blame - src/security/Session.cc
Merged from trunk rev.14899
[thirdparty/squid.git] / src / security / Session.cc
CommitLineData
824d4656
AJ
1/*
2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
5d9a65df
AJ
9/* DEBUG: section 83 TLS session management */
10
824d4656
AJ
11#include "squid.h"
12#include "anyp/PortCfg.h"
13#include "base/RunnersRegistry.h"
5d9a65df 14#include "Debug.h"
86f77270 15#include "fde.h"
824d4656
AJ
16#include "ipc/MemMap.h"
17#include "security/Session.h"
18#include "SquidConfig.h"
86f77270 19#include "ssl/bio.h"
824d4656
AJ
20
21#define SSL_SESSION_ID_SIZE 32
22#define SSL_SESSION_MAX_SIZE 10*1024
23
86f77270
AJ
24static bool
25CreateSession(const Security::ContextPointer &ctx, const Comm::ConnectionPointer &conn, Security::Io::Type type, const char *squidCtx)
26{
27 if (!Comm::IsConnOpen(conn)) {
28 debugs(83, DBG_IMPORTANT, "Gone connection");
29 return false;
30 }
31
32 const char *errAction = "with no TLS/SSL library";
33#if USE_OPENSSL
34 int errCode = 0;
35 if (auto ssl = SSL_new(ctx.get())) {
36 const int fd = conn->fd;
37 // without BIO, we would call SSL_set_fd(ssl, fd) instead
38 if (BIO *bio = Ssl::Bio::Create(fd, type)) {
39 Ssl::Bio::Link(ssl, bio); // cannot fail
40
41 fd_table[fd].ssl.resetWithoutLocking(ssl);
42 fd_table[fd].read_method = &ssl_read_method;
43 fd_table[fd].write_method = &ssl_write_method;
44 fd_note(fd, squidCtx);
45 return true;
46 }
47 errCode = ERR_get_error();
48 errAction = "failed to initialize I/O";
49 SSL_free(ssl);
50 } else {
51 errCode = ERR_get_error();
52 errAction = "failed to allocate handle";
53 }
54 debugs(83, DBG_IMPORTANT, "ERROR: " << squidCtx << ' ' << errAction <<
55 ": " << ERR_error_string(errCode, nullptr));
56#else
57 debugs(83, DBG_IMPORTANT, "ERROR: " << squidCtx << ' ' << errAction);
58#endif
59 return false;
60}
61
62bool
63Security::CreateClientSession(const Security::ContextPointer &ctx, const Comm::ConnectionPointer &c, const char *squidCtx)
64{
65 return CreateSession(ctx, c, Security::Io::BIO_TO_SERVER, squidCtx);
66}
67
68bool
69Security::CreateServerSession(const Security::ContextPointer &ctx, const Comm::ConnectionPointer &c, const char *squidCtx)
70{
71 return CreateSession(ctx, c, Security::Io::BIO_TO_CLIENT, squidCtx);
72}
73
5d9a65df
AJ
74bool
75Security::SessionIsResumed(const Security::SessionPointer &s)
76{
77 bool result = false;
78#if USE_OPENSSL
79 result = SSL_session_reused(s.get()) == 1;
80#elif USE_GNUTLS
81 result = gnutls_session_is_resumed(s.get()) != 0;
82#endif
83 debugs(83, 7, "session=" << (void*)s.get() << ", query? answer: " << (result ? 'T' : 'F') );
84 return result;
85}
86
87void
88Security::MaybeGetSessionResumeData(const Security::SessionPointer &s, Security::SessionStatePointer &data)
89{
90 if (!SessionIsResumed(s)) {
91#if USE_OPENSSL
92 // nil is valid for SSL_get1_session(), it cannot fail.
93 data.reset(SSL_get1_session(s.get()));
94#elif USE_GNUTLS
95 gnutls_datum_t *tmp = nullptr;
96 const auto x = gnutls_session_get_data2(s.get(), tmp);
97 if (x != GNUTLS_E_SUCCESS) {
98 debugs(83, 3, "session=" << (void*)s.get() << " error: " << gnutls_strerror(x));
99 }
100 data.reset(tmp);
101#endif
102 debugs(83, 5, "session=" << (void*)s.get() << " data=" << (void*)data.get());
103 } else {
104 debugs(83, 5, "session=" << (void*)s.get() << " data=" << (void*)data.get() << ", do nothing.");
105 }
106}
107
108void
109Security::SetSessionResumeData(const Security::SessionPointer &s, const Security::SessionStatePointer &data)
110{
111 if (data) {
112#if USE_OPENSSL
113 if (!SSL_set_session(s.get(), data.get())) {
114 const auto ssl_error = ERR_get_error();
115 debugs(83, 3, "session=" << (void*)s.get() << " data=" << (void*)data.get() <<
116 " resume error: " << ERR_error_string(ssl_error, nullptr));
117 }
118#elif USE_GNUTLS
119 const auto x = gnutls_session_set_data(s.get(), data->data, data->size);
120 if (x != GNUTLS_E_SUCCESS) {
121 debugs(83, 3, "session=" << (void*)s.get() << " data=" << (void*)data.get() <<
122 " resume error: " << gnutls_strerror(x));
123 }
124#else
125 // critical because, how did it get here?
126 debugs(83, DBG_CRITICAL, "no TLS library. session=" << (void*)s.get() << " data=" << (void*)data.get());
127#endif
128 debugs(83, 5, "session=" << (void*)s.get() << " data=" << (void*)data.get());
129 } else {
130 debugs(83, 5, "session=" << (void*)s.get() << " no resume data");
131 }
132}
133
824d4656
AJ
134static bool
135isTlsServer()
136{
137 for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
138 if (s->secure.encryptTransport)
139 return true;
140 if (s->flags.tunnelSslBumping)
141 return true;
142 }
143
144 return false;
145}
146
147void
148initializeSessionCache()
149{
150#if USE_OPENSSL
151 // Check if the MemMap keys and data are enough big to hold
152 // session ids and session data
153 assert(SSL_SESSION_ID_SIZE >= MEMMAP_SLOT_KEY_SIZE);
154 assert(SSL_SESSION_MAX_SIZE >= MEMMAP_SLOT_DATA_SIZE);
155
156 int configuredItems = ::Config.SSL.sessionCacheSize / sizeof(Ipc::MemMap::Slot);
157 if (IamWorkerProcess() && configuredItems)
158 Ssl::SessionCache = new Ipc::MemMap(Ssl::SessionCacheName);
159 else {
160 Ssl::SessionCache = nullptr;
161 return;
162 }
163
164 for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
b23f5f9c
AJ
165 if (s->secure.staticContext)
166 Ssl::SetSessionCallbacks(s->secure.staticContext);
824d4656
AJ
167 }
168#endif
169}
170
171/// initializes shared memory segments used by MemStore
172class SharedSessionCacheRr: public Ipc::Mem::RegisteredRunner
173{
174public:
175 /* RegisteredRunner API */
176 SharedSessionCacheRr(): owner(nullptr) {}
177 virtual void useConfig();
178 virtual ~SharedSessionCacheRr();
179
180protected:
181 virtual void create();
182
183private:
184 Ipc::MemMap::Owner *owner;
185};
186
187RunnerRegistrationEntry(SharedSessionCacheRr);
188
189void
190SharedSessionCacheRr::useConfig()
191{
192#if USE_OPENSSL // while Ssl:: bits in use
193 if (Ssl::SessionCache || !isTlsServer()) //no need to configure ssl session cache.
194 return;
195
196 Ipc::Mem::RegisteredRunner::useConfig();
197 initializeSessionCache();
198#endif
199}
200
201void
202SharedSessionCacheRr::create()
203{
204 if (!isTlsServer()) //no need to configure ssl session cache.
205 return;
206
207#if USE_OPENSSL // while Ssl:: bits in use
208 if (int items = Config.SSL.sessionCacheSize / sizeof(Ipc::MemMap::Slot))
209 owner = Ipc::MemMap::Init(Ssl::SessionCacheName, items);
210#endif
211}
212
213SharedSessionCacheRr::~SharedSessionCacheRr()
214{
215 // XXX: Enable after testing to reduce at-exit memory "leaks".
216 // delete Ssl::SessionCache;
217
218 delete owner;
219}
220