]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/security/Session.cc
2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 83 TLS session management */
12 #include "anyp/PortCfg.h"
13 #include "base/RunnersRegistry.h"
17 #include "ipc/MemMap.h"
18 #include "security/Session.h"
19 #include "SquidConfig.h"
22 #define SSL_SESSION_ID_SIZE 32
23 #define SSL_SESSION_MAX_SIZE 10*1024
25 #if USE_OPENSSL || USE_GNUTLS
27 tls_read_method(int fd
, char *buf
, int len
)
29 auto session
= fd_table
[fd
].ssl
.get();
31 #if DONT_DO_THIS && USE_OPENSSL
32 if (!SSL_is_init_finished(session
)) {
39 int i
= SSL_read(session
, buf
, len
);
41 int i
= gnutls_record_recv(session
, buf
, len
);
44 debugs(83, 8, "TLS FD " << fd
<< " session=" << (void*)session
<< " " << i
<< " bytes");
45 (void)VALGRIND_MAKE_MEM_DEFINED(buf
, i
);
49 if (i
> 0 && SSL_pending(session
) > 0) {
51 if (i
> 0 && gnutls_record_check_pending(session
) > 0) {
53 debugs(83, 2, "TLS FD " << fd
<< " is pending");
54 fd_table
[fd
].flags
.read_pending
= true;
56 fd_table
[fd
].flags
.read_pending
= false;
62 tls_write_method(int fd
, const char *buf
, int len
)
64 auto session
= fd_table
[fd
].ssl
.get();
67 if (!SSL_is_init_finished(session
)) {
74 int i
= SSL_write(session
, buf
, len
);
76 int i
= gnutls_record_send(session
, buf
, len
);
80 debugs(83, 8, "TLS FD " << fd
<< " session=" << (void*)session
<< " " << i
<< " bytes");
87 CreateSession(const Security::ContextPointer
&ctx
, const Comm::ConnectionPointer
&conn
, Security::Io::Type type
, const char *squidCtx
)
89 if (!Comm::IsConnOpen(conn
)) {
90 debugs(83, DBG_IMPORTANT
, "Gone connection");
94 #if USE_OPENSSL || USE_GNUTLS
96 const char *errAction
= "with no TLS/SSL library";
99 Security::SessionPointer
session(SSL_new(ctx
.get()), [](SSL
*p
) {
100 debugs(83, 5, "SSL_free session=" << (void*)p
);
103 debugs(83, 5, "SSL_new session=" << (void*)session
.get());
105 errCode
= ERR_get_error();
106 errAction
= "failed to allocate handle";
109 gnutls_session_t tmp
;
110 errCode
= gnutls_init(&tmp
, static_cast<unsigned int>(type
));
111 Security::SessionPointer
session(tmp
, [](gnutls_session_t p
) {
112 debugs(83, 5, "gnutls_deinit session=" << (void*)p
);
115 debugs(83, 5, "gnutls_init session=" << (void*)session
.get());
116 if (errCode
!= GNUTLS_E_SUCCESS
) {
118 errAction
= "failed to initialize session";
123 const int fd
= conn
->fd
;
126 // without BIO, we would call SSL_set_fd(ssl.get(), fd) instead
127 if (BIO
*bio
= Ssl::Bio::Create(fd
, type
)) {
128 Ssl::Bio::Link(session
.get(), bio
); // cannot fail
130 errCode
= gnutls_credentials_set(session
.get(), GNUTLS_CRD_CERTIFICATE
, ctx
.get());
131 if (errCode
== GNUTLS_E_SUCCESS
) {
134 debugs(83, 5, "link FD " << fd
<< " to TLS session=" << (void*)session
.get());
135 fd_table
[fd
].ssl
= session
;
136 fd_table
[fd
].read_method
= &tls_read_method
;
137 fd_table
[fd
].write_method
= &tls_write_method
;
138 fd_note(fd
, squidCtx
);
143 errCode
= ERR_get_error();
144 errAction
= "failed to initialize I/O";
146 errAction
= "failed to assign credentials";
150 debugs(83, DBG_IMPORTANT
, "ERROR: " << squidCtx
<< ' ' << errAction
<<
151 ": " << (errCode
!= 0 ? Security::ErrorString(errCode
) : ""));
157 Security::CreateClientSession(const Security::ContextPointer
&ctx
, const Comm::ConnectionPointer
&c
, const char *squidCtx
)
159 return CreateSession(ctx
, c
, Security::Io::BIO_TO_SERVER
, squidCtx
);
163 Security::CreateServerSession(const Security::ContextPointer
&ctx
, const Comm::ConnectionPointer
&c
, const char *squidCtx
)
165 return CreateSession(ctx
, c
, Security::Io::BIO_TO_CLIENT
, squidCtx
);
169 Security::SessionClose(const Security::SessionPointer
&s
, const int fdOnError
)
171 debugs(83, 5, "session=" << (void*)s
.get());
172 if (s
&& fdOnError
== -1) {
174 SSL_shutdown(s
.get());
176 gnutls_bye(s
.get(), GNUTLS_SHUT_RDWR
);
181 // XXX: should probably be done for OpenSSL too, but that needs testing.
182 if (fdOnError
!= -1) {
183 debugs(83, 5, "unlink FD " << fdOnError
<< " from TLS session=" << (void*)fd_table
[fdOnError
].ssl
.get());
184 fd_table
[fdOnError
].ssl
.reset();
185 fd_table
[fdOnError
].read_method
= &default_read_method
;
186 fd_table
[fdOnError
].write_method
= &default_write_method
;
187 fd_note(fdOnError
, "TLS error");
193 Security::SessionIsResumed(const Security::SessionPointer
&s
)
197 result
= SSL_session_reused(s
.get()) == 1;
199 result
= gnutls_session_is_resumed(s
.get()) != 0;
201 debugs(83, 7, "session=" << (void*)s
.get() << ", query? answer: " << (result
? 'T' : 'F') );
206 Security::MaybeGetSessionResumeData(const Security::SessionPointer
&s
, Security::SessionStatePointer
&data
)
208 if (!SessionIsResumed(s
)) {
210 // nil is valid for SSL_get1_session(), it cannot fail.
211 data
.reset(SSL_get1_session(s
.get()));
213 gnutls_datum_t
*tmp
= nullptr;
214 const auto x
= gnutls_session_get_data2(s
.get(), tmp
);
215 if (x
!= GNUTLS_E_SUCCESS
) {
216 debugs(83, 3, "session=" << (void*)s
.get() << " error: " << Security::ErrorString(x
));
220 debugs(83, 5, "session=" << (void*)s
.get() << " data=" << (void*)data
.get());
222 debugs(83, 5, "session=" << (void*)s
.get() << " data=" << (void*)data
.get() << ", do nothing.");
227 Security::SetSessionResumeData(const Security::SessionPointer
&s
, const Security::SessionStatePointer
&data
)
231 if (!SSL_set_session(s
.get(), data
.get())) {
232 const auto ssl_error
= ERR_get_error();
233 debugs(83, 3, "session=" << (void*)s
.get() << " data=" << (void*)data
.get() <<
234 " resume error: " << Security::ErrorString(ssl_error
));
237 const auto x
= gnutls_session_set_data(s
.get(), data
->data
, data
->size
);
238 if (x
!= GNUTLS_E_SUCCESS
) {
239 debugs(83, 3, "session=" << (void*)s
.get() << " data=" << (void*)data
.get() <<
240 " resume error: " << Security::ErrorString(x
));
243 // critical because, how did it get here?
244 debugs(83, DBG_CRITICAL
, "no TLS library. session=" << (void*)s
.get() << " data=" << (void*)data
.get());
246 debugs(83, 5, "session=" << (void*)s
.get() << " data=" << (void*)data
.get());
248 debugs(83, 5, "session=" << (void*)s
.get() << " no resume data");
255 for (AnyP::PortCfgPointer s
= HttpPortList
; s
!= nullptr; s
= s
->next
) {
256 if (s
->secure
.encryptTransport
)
258 if (s
->flags
.tunnelSslBumping
)
266 initializeSessionCache()
269 // Check if the MemMap keys and data are enough big to hold
270 // session ids and session data
271 assert(SSL_SESSION_ID_SIZE
>= MEMMAP_SLOT_KEY_SIZE
);
272 assert(SSL_SESSION_MAX_SIZE
>= MEMMAP_SLOT_DATA_SIZE
);
274 int configuredItems
= ::Config
.SSL
.sessionCacheSize
/ sizeof(Ipc::MemMap::Slot
);
275 if (IamWorkerProcess() && configuredItems
)
276 Ssl::SessionCache
= new Ipc::MemMap(Ssl::SessionCacheName
);
278 Ssl::SessionCache
= nullptr;
282 for (AnyP::PortCfgPointer s
= HttpPortList
; s
!= nullptr; s
= s
->next
) {
283 if (s
->secure
.staticContext
)
284 Ssl::SetSessionCallbacks(s
->secure
.staticContext
);
289 /// initializes shared memory segments used by MemStore
290 class SharedSessionCacheRr
: public Ipc::Mem::RegisteredRunner
293 /* RegisteredRunner API */
294 SharedSessionCacheRr(): owner(nullptr) {}
295 virtual void useConfig();
296 virtual ~SharedSessionCacheRr();
299 virtual void create();
302 Ipc::MemMap::Owner
*owner
;
305 RunnerRegistrationEntry(SharedSessionCacheRr
);
308 SharedSessionCacheRr::useConfig()
310 #if USE_OPENSSL // while Ssl:: bits in use
311 if (Ssl::SessionCache
|| !isTlsServer()) //no need to configure ssl session cache.
314 Ipc::Mem::RegisteredRunner::useConfig();
315 initializeSessionCache();
320 SharedSessionCacheRr::create()
322 if (!isTlsServer()) //no need to configure ssl session cache.
325 #if USE_OPENSSL // while Ssl:: bits in use
326 if (int items
= Config
.SSL
.sessionCacheSize
/ sizeof(Ipc::MemMap::Slot
))
327 owner
= Ipc::MemMap::Init(Ssl::SessionCacheName
, items
);
331 SharedSessionCacheRr::~SharedSessionCacheRr()
333 // XXX: Enable after testing to reduce at-exit memory "leaks".
334 // delete Ssl::SessionCache;