From: Amos Jeffries Date: Sun, 27 Nov 2016 11:51:20 +0000 (+1300) Subject: Implement GnuTLS session logics in libsecurity X-Git-Tag: M-staged-PR71~284^2~35 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=087b94cbbaa9f4147efa8cf833cac19a0db40efa;p=thirdparty%2Fsquid.git Implement GnuTLS session logics in libsecurity --- diff --git a/src/Makefile.am b/src/Makefile.am index 2e1c7923e7..1e6db30592 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3040,10 +3040,10 @@ tests_testUfs_LDADD = \ acl/libacls.la \ DiskIO/libdiskio.la \ acl/libapi.la \ + anyp/libanyp.la \ $(SSL_LIBS) \ ipc/libipc.la \ comm/libcomm.la \ - anyp/libanyp.la \ dns/libdns.la \ base/libbase.la \ ip/libip.la \ diff --git a/src/comm.cc b/src/comm.cc index 9b451d7f4f..cdeb67aa1b 100644 --- a/src/comm.cc +++ b/src/comm.cc @@ -764,10 +764,7 @@ commLingerTimeout(const FdeCbParams ¶ms) void comm_lingering_close(int fd) { -#if USE_OPENSSL - if (fd_table[fd].ssl) - ssl_shutdown_method(fd_table[fd].ssl); -#endif + Security::SessionClose(fd_table[fd].ssl); if (shutdown(fd, 1) < 0) { comm_close(fd); @@ -825,14 +822,11 @@ old_comm_reset_close(int fd) comm_close(fd); } -#if USE_OPENSSL void -commStartSslClose(const FdeCbParams ¶ms) +commStartTlsClose(const FdeCbParams ¶ms) { - assert(fd_table[params.fd].ssl); - ssl_shutdown_method(fd_table[params.fd].ssl.get()); + Security::SessionClose(fd_table[params.fd].ssl); } -#endif void comm_close_complete(const FdeCbParams ¶ms) @@ -890,15 +884,13 @@ _comm_close(int fd, char const *file, int line) F->flags.close_request = true; -#if USE_OPENSSL if (F->ssl) { - AsyncCall::Pointer startCall=commCbCall(5,4, "commStartSslClose", - FdeCbPtrFun(commStartSslClose, NULL)); + AsyncCall::Pointer startCall=commCbCall(5,4, "commStartTlsClose", + FdeCbPtrFun(commStartTlsClose, nullptr)); FdeCbParams &startParams = GetCommParams(startCall); startParams.fd = fd; ScheduleCallHere(startCall); } -#endif // a half-closed fd may lack a reader, so we stop monitoring explicitly if (commHasHalfClosedMonitor(fd)) diff --git a/src/security/PeerConnector.cc b/src/security/PeerConnector.cc index a7d256686c..3677c5d7b8 100644 --- a/src/security/PeerConnector.cc +++ b/src/security/PeerConnector.cc @@ -178,6 +178,8 @@ Security::PeerConnector::negotiate() #if USE_OPENSSL const int result = SSL_connect(fd_table[fd].ssl.get()); +#elif USE_GNUTLS + const int result = gnutls_handshake(fd_table[fd].ssl.get()); #else const int result = -1; #endif @@ -386,6 +388,13 @@ Security::PeerConnector::handleNegotiateError(const int ret) // Log connection details, if any recordNegotiationDetails(); noteNegotiationError(ret, ssl_error, ssl_lib_error); + +#elif USE_GNUTLS + // TODO: handle specific errors individually like above + if (gnutls_error_is_fatal(ret) == 0) { + noteWantRead(); + return; + } #endif } diff --git a/src/security/Session.cc b/src/security/Session.cc index e8c24e8d14..3dcf102b26 100644 --- a/src/security/Session.cc +++ b/src/security/Session.cc @@ -12,6 +12,7 @@ #include "anyp/PortCfg.h" #include "base/RunnersRegistry.h" #include "Debug.h" +#include "fd.h" #include "fde.h" #include "ipc/MemMap.h" #include "security/Session.h" @@ -21,6 +22,63 @@ #define SSL_SESSION_ID_SIZE 32 #define SSL_SESSION_MAX_SIZE 10*1024 +#if USE_OPENSSL || USE_GNUTLS +static int +tls_read_method(int fd, char *buf, int len) +{ + auto session = fd_table[fd].ssl.get(); + +#if DONT_DO_THIS && USE_OPENSSL + if (!SSL_is_init_finished(session)) { + errno = ENOTCONN; + return -1; + } +#endif + +#if USE_OPENSSL + int i = SSL_read(session, buf, len); +#elif USE_GNUTLS + int i = gnutls_record_recv(session, buf, len); +#endif + if (i > 0) { + (void)VALGRIND_MAKE_MEM_DEFINED(buf, i); + } + +#if USE_OPENSSL + if (i > 0 && SSL_pending(session) > 0) { +#elif USE_GNUTLS + if (i > 0 && gnutls_record_check_pending(session) > 0) { +#endif + debugs(83, 2, "TLS FD " << fd << " is pending"); + fd_table[fd].flags.read_pending = true; + } else + fd_table[fd].flags.read_pending = false; + + return i; +} + +static int +tls_write_method(int fd, const char *buf, int len) +{ + auto session = fd_table[fd].ssl.get(); + +#if USE_OPENSSL + if (!SSL_is_init_finished(session)) { + errno = ENOTCONN; + return -1; + } +#endif + +#if USE_OPENSSL + int i = SSL_write(session, buf, len); +#elif USE_GNUTLS + int i = gnutls_record_send(session, buf, len); +#endif + + return i; +} +#endif + static bool CreateSession(const Security::ContextPointer &ctx, const Comm::ConnectionPointer &conn, Security::Io::Type type, const char *squidCtx) { @@ -29,31 +87,56 @@ CreateSession(const Security::ContextPointer &ctx, const Comm::ConnectionPointer return false; } +#if USE_OPENSSL || USE_GNUTLS + const char *errAction = "with no TLS/SSL library"; int errCode = 0; #if USE_OPENSSL - Security::SessionPointer ssl(SSL_new(ctx.get())); - if (ssl) { + Security::SessionPointer session(SSL_new(ctx.get())); + if (!session) { + errCode = ERR_get_error(); + errAction = "failed to allocate handle"; + } +#elif USE_GNUTLS + gnutls_session_t tmp; + errCode = gnutls_init(&tmp, static_cast(type)); + Security::SessionPointer session(tmp); + if (errCode != GNUTLS_E_SUCCESS) { + session.reset(); + errAction = "failed to initialize session"; + } +#endif + + if (session) { const int fd = conn->fd; + +#if USE_OPENSSL // without BIO, we would call SSL_set_fd(ssl.get(), fd) instead if (BIO *bio = Ssl::Bio::Create(fd, type)) { - Ssl::Bio::Link(ssl.get(), bio); // cannot fail + Ssl::Bio::Link(session.get(), bio); // cannot fail +#elif USE_GNUTLS + errCode = gnutls_credentials_set(session.get(), GNUTLS_CRD_CERTIFICATE, ctx.get()); + if (errCode == GNUTLS_E_SUCCESS) { +#endif - fd_table[fd].ssl = ssl; - fd_table[fd].read_method = &ssl_read_method; - fd_table[fd].write_method = &ssl_write_method; + fd_table[fd].ssl = session; + fd_table[fd].read_method = &tls_read_method; + fd_table[fd].write_method = &tls_write_method; fd_note(fd, squidCtx); return true; } + +#if USE_OPENSSL errCode = ERR_get_error(); errAction = "failed to initialize I/O"; - } else { - errCode = ERR_get_error(); - errAction = "failed to allocate handle"; - } +#elif USE_GNUTLS + errAction = "failed to assign credentials"; #endif + } + debugs(83, DBG_IMPORTANT, "ERROR: " << squidCtx << ' ' << errAction << ": " << (errCode != 0 ? Security::ErrorString(errCode) : "")); +#endif return false; } @@ -69,6 +152,19 @@ Security::CreateServerSession(const Security::ContextPointer &ctx, const Comm::C return CreateSession(ctx, c, Security::Io::BIO_TO_CLIENT, squidCtx); } +void +Security::SessionClose(const Security::SessionPointer &s) +{ + debugs(83, 5, "session=" << (void*)s.get()); + if (s) { +#if USE_OPENSSL + SSL_shutdown(s.get()); +#elif USE_GNUTLS + gnutls_bye(s.get(), GNUTLS_SHUT_RDWR); +#endif + } +} + bool Security::SessionIsResumed(const Security::SessionPointer &s) { diff --git a/src/security/Session.h b/src/security/Session.h index 50a5062d19..182ca8da57 100644 --- a/src/security/Session.h +++ b/src/security/Session.h @@ -66,6 +66,9 @@ typedef std::unique_ptr SessionStatePointer; #endif +/// close an active TLS session +void SessionClose(const Security::SessionPointer &); + /// whether the session is a resumed one bool SessionIsResumed(const Security::SessionPointer &); diff --git a/src/security/forward.h b/src/security/forward.h index 201f519230..963121b79c 100644 --- a/src/security/forward.h +++ b/src/security/forward.h @@ -111,8 +111,13 @@ typedef std::unordered_set Errors; namespace Io { enum Type { +#if USE_GNUTLS + BIO_TO_CLIENT = GNUTLS_CLIENT, + BIO_TO_SERVER = GNUTLS_SERVER +#else BIO_TO_CLIENT = 6000, BIO_TO_SERVER +#endif }; } // namespace Io diff --git a/src/ssl/support.cc b/src/ssl/support.cc index 24366da894..b63222c335 100644 --- a/src/ssl/support.cc +++ b/src/ssl/support.cc @@ -691,55 +691,6 @@ Ssl::InitClientContext(Security::ContextPointer &ctx, Security::PeerOptions &pee return true; } -/// \ingroup ServerProtocolSSLInternal -int -ssl_read_method(int fd, char *buf, int len) -{ - auto ssl = fd_table[fd].ssl.get(); - -#if DONT_DO_THIS - - if (!SSL_is_init_finished(ssl)) { - errno = ENOTCONN; - return -1; - } - -#endif - - int i = SSL_read(ssl, buf, len); - if (i > 0) { - (void)VALGRIND_MAKE_MEM_DEFINED(buf, i); - } - - if (i > 0 && SSL_pending(ssl) > 0) { - debugs(83, 2, "SSL FD " << fd << " is pending"); - fd_table[fd].flags.read_pending = true; - } else - fd_table[fd].flags.read_pending = false; - - return i; -} - -/// \ingroup ServerProtocolSSLInternal -int -ssl_write_method(int fd, const char *buf, int len) -{ - auto ssl = fd_table[fd].ssl.get(); - if (!SSL_is_init_finished(ssl)) { - errno = ENOTCONN; - return -1; - } - - int i = SSL_write(ssl, buf, len); - return i; -} - -void -ssl_shutdown_method(SSL *ssl) -{ - SSL_shutdown(ssl); -} - /// \ingroup ServerProtocolSSLInternal static const char * ssl_get_attribute(X509_NAME * name, const char *attribute_name) diff --git a/src/ssl/support.h b/src/ssl/support.h index 1070cc2d49..97685974c5 100644 --- a/src/ssl/support.h +++ b/src/ssl/support.h @@ -91,15 +91,6 @@ inline int X509_up_ref(X509 *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOC } //namespace Ssl -/// \ingroup ServerProtocolSSLAPI -int ssl_read_method(int, char *, int); - -/// \ingroup ServerProtocolSSLAPI -int ssl_write_method(int, const char *, int); - -/// \ingroup ServerProtocolSSLAPI -void ssl_shutdown_method(SSL *ssl); - /// \ingroup ServerProtocolSSLAPI const char *sslGetUserEmail(SSL *ssl); diff --git a/src/tests/stub_libsecurity.cc b/src/tests/stub_libsecurity.cc index 9796f6f7e7..fb3372caa0 100644 --- a/src/tests/stub_libsecurity.cc +++ b/src/tests/stub_libsecurity.cc @@ -91,6 +91,7 @@ void Security::ServerOptions::updateContextEecdh(Security::ContextPointer &) STU namespace Security { bool CreateClientSession(const Security::ContextPointer &, const Comm::ConnectionPointer &, const char *) STUB_RETVAL(false) bool CreateServerSession(const Security::ContextPointer &, const Comm::ConnectionPointer &, const char *) STUB_RETVAL(false) +void SessionClose(const Security::SessionPointer &) STUB 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 diff --git a/src/tests/stub_libsslsquid.cc b/src/tests/stub_libsslsquid.cc index 15c410243a..6666477960 100644 --- a/src/tests/stub_libsslsquid.cc +++ b/src/tests/stub_libsslsquid.cc @@ -53,9 +53,6 @@ namespace Ssl bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &) STUB_RETVAL(false) bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, long, const char *) STUB_RETVAL(false) } // namespace Ssl -int ssl_read_method(int, char *, int) STUB_RETVAL(0) -int ssl_write_method(int, const char *, int) STUB_RETVAL(0) -void ssl_shutdown_method(SSL *ssl) STUB const char *sslGetUserEmail(SSL *ssl) STUB_RETVAL(NULL) const char *sslGetUserAttribute(SSL *ssl, const char *attribute_name) STUB_RETVAL(NULL) const char *sslGetCAAttribute(SSL *ssl, const char *attribute_name) STUB_RETVAL(NULL)