]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Implement GnuTLS session logics in libsecurity
authorAmos Jeffries <squid3@treenet.co.nz>
Sun, 27 Nov 2016 11:51:20 +0000 (00:51 +1300)
committerAmos Jeffries <squid3@treenet.co.nz>
Sun, 27 Nov 2016 11:51:20 +0000 (00:51 +1300)
src/Makefile.am
src/comm.cc
src/security/PeerConnector.cc
src/security/Session.cc
src/security/Session.h
src/security/forward.h
src/ssl/support.cc
src/ssl/support.h
src/tests/stub_libsecurity.cc
src/tests/stub_libsslsquid.cc

index 2e1c7923e79be96e0189737c6560451af02f555c..1e6db30592851f1f5c0d3f051eee9e38bd58572a 100644 (file)
@@ -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 \
index 9b451d7f4fc0d96f7484d6f2a7dc4689b0befff7..cdeb67aa1bdc63d7c2d9ebbb8d6eed511add06a1 100644 (file)
@@ -764,10 +764,7 @@ commLingerTimeout(const FdeCbParams &params)
 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 &params)
+commStartTlsClose(const FdeCbParams &params)
 {
-    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 &params)
@@ -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<FdeCbParams>(startCall);
         startParams.fd = fd;
         ScheduleCallHere(startCall);
     }
-#endif
 
     // a half-closed fd may lack a reader, so we stop monitoring explicitly
     if (commHasHalfClosedMonitor(fd))
index a7d256686cb28ec9f3eba1cb732897d1c449100b..3677c5d7b81e057f7b805856b52b4fa033a0138b 100644 (file)
@@ -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
 }
 
index e8c24e8d1426da91387630a4f224f0698acebfa2..3dcf102b262d6bab4fe41ecf52027b2c39bee37f 100644 (file)
@@ -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"
 #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<unsigned int>(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)
 {
index 50a5062d1986bf6e6517be2f49810b1bef32ef6e..182ca8da57805f612fdc2dc7982756704ee8e9e1 100644 (file)
@@ -66,6 +66,9 @@ typedef std::unique_ptr<int> SessionStatePointer;
 
 #endif
 
+/// close an active TLS session
+void SessionClose(const Security::SessionPointer &);
+
 /// whether the session is a resumed one
 bool SessionIsResumed(const Security::SessionPointer &);
 
index 201f519230d6e6a7bec937972185283f688eb913..963121b79cb83cf8f566221990418bdcf9a50380 100644 (file)
@@ -111,8 +111,13 @@ typedef std::unordered_set<Security::ErrorCode> 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
index 24366da894538084897b967e0a9dc8ffc80ac69a..b63222c335748c5e36e73896577b12646de94e09 100644 (file)
@@ -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)
index 1070cc2d498b446556a45842fe782c71e33d5c66..97685974c5009fb26da6a14089cd33b4dc5914ea 100644 (file)
@@ -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);
 
index 9796f6f7e79f8616a8c243103e83eb02c1b47980..fb3372caa0d5c44da7f45b3c6136182c72caf3ab 100644 (file)
@@ -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
index 15c410243a50114ce928bcecf1575e7487a86049..66664779609c977e46b45018c6024525c33b5f91 100644 (file)
@@ -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)