]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Validate server certificates without bumping
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Mon, 6 Oct 2014 14:53:40 +0000 (17:53 +0300)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Mon, 6 Oct 2014 14:53:40 +0000 (17:53 +0300)
This patch add support for the "Validate server certificates without bumping"
use case described on the Peek and Splice wiki page:
    http://wiki.squid-cache.org/Features/SslPeekAndSplice

This patch send to the certificate validation helper the  certificates and
errors found in SslBump3 step, even if the splicing mode selected.
In the case the validation helper found errors in certificates an error
page returned to the http client.

The SSL error forwarding is controlled by ACLs along these lines:

   sslproxy_cert_error allow sslBoringErrors
   sslproxy_cert_error allow serversWithInvalidCerts
   sslproxy_cert_error deny all

This is a Measurement Factory project

src/ssl/PeerConnector.cc
src/ssl/PeerConnector.h
src/tunnel.cc

index c618de25be53ab0e3158e6320f45ebcb18560a79..607d881a978df5d9524556e1b1ac3fd19f8c886f 100644 (file)
@@ -44,7 +44,8 @@ Ssl::PeerConnector::PeerConnector(
         clientConn(aClientConn),
         callback(aCallback),
         negotiationTimeout(timeout),
-        startTime(squid_curtime)
+        startTime(squid_curtime),
+        splice(false)
 {
     // if this throws, the caller's cb dialer is not our CbDialer
     Must(dynamic_cast<CbDialer*>(callback->getDialer()));
@@ -230,6 +231,25 @@ Ssl::PeerConnector::negotiateSsl()
         return; // we might be gone by now
     }
 
+    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 (!sslFinalized())
+        return;
+
+    callBack();
+}
+
+bool
+Ssl::PeerConnector::sslFinalized()
+{
+    const int fd = serverConnection()->fd;
+    SSL *ssl = fd_table[fd].ssl;
+
     if (request->clientConnectionManager.valid()) {
         // remember the server certificate from the ErrorDetail object
         if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
@@ -241,13 +261,6 @@ Ssl::PeerConnector::negotiateSsl()
         }
     }
 
-    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 (Ssl::TheConfig.ssl_crt_validator) {
         Ssl::CertValidationRequest validationRequest;
         // WARNING: Currently we do not use any locking for any of the
@@ -264,7 +277,7 @@ Ssl::PeerConnector::negotiateSsl()
         try {
             debugs(83, 5, "Sending SSL certificate for validation to ssl_crtvd.");
             Ssl::CertValidationHelper::GetInstance()->sslSubmit(validationRequest, sslCrtvdHandleReplyWrapper, this);
-            return;
+            return false;
         } catch (const std::exception &e) {
             debugs(83, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtvd " <<
                    "request for " << validationRequest.domainName <<
@@ -277,14 +290,13 @@ Ssl::PeerConnector::negotiateSsl()
                 peerConnectFailed(serverConnection()->getPeer());
             }
             serverConn->close();
-            return;
+            return true;
         }
     }
-
-    callBack();
+    return true;
 }
 
-void switchToTunnel(HttpRequest *request, int *status_ptr, Comm::ConnectionPointer & clientConn, Comm::ConnectionPointer &srvConn);
+void switchToTunnel(HttpRequest *request, Comm::ConnectionPointer & clientConn, Comm::ConnectionPointer &srvConn);
 
 void
 Ssl::PeerConnector::cbCheckForPeekAndSpliceDone(allow_t answer, void *data)
@@ -346,9 +358,12 @@ Ssl::PeerConnector::checkForPeekAndSpliceDone(Ssl::BumpMode const action)
         Comm::SetSelect(serverConn->fd, COMM_SELECT_WRITE, &NegotiateSsl, this, 0);
         debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn->fd);
     } else {
-        static int status_code = 0;
-        debugs(83,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << serverConn->fd);
-        switchToTunnel(request.getRaw(), &status_code, clientConn, serverConn);
+        splice = true;
+        // Ssl Negotiation stops here. Last SSL checks for valid certificates 
+        // and if done, switch to tunnel mode
+        if (sslFinalized())
+            switchToTunnel(request.getRaw(), clientConn, serverConn);
+        return false;
     }
 }
 
@@ -377,7 +392,10 @@ Ssl::PeerConnector::sslCrtvdHandleReply(Ssl::CertValidationResponse const &valid
         validatorFailed = true;
 
     if (!errDetails && !validatorFailed) {
-        callBack();
+        if (splice)
+            switchToTunnel(request.getRaw(), clientConn, serverConn);
+        else
+            callBack();
         return;
     }
 
index 7f9e680621cd77548dd74a1ffe5ea479a3cd1a61..1f453cdaf6a0b13632c099980aae1da8848ed30a 100644 (file)
@@ -116,6 +116,11 @@ protected:
     /// It is called multiple times untill the negotiation finish or aborted.
     void negotiateSsl();
 
+    /// Called after SSL negotiations have finished. Cleans up SSL state.
+    /// Returns false if we are now waiting for the certs validation job.
+    /// Otherwise, returns true, regardless of negotiation success/failure.
+    bool sslFinalized();
+
     /// Initiates the ssl_bump acl check in step3 SSL bump step to decide
     /// about bumping, splicing or terminating the connection.
     void checkForPeekAndSplice();
@@ -165,6 +170,7 @@ private:
     AsyncCall::Pointer closeHandler; ///< we call this when the connection closed
     time_t negotiationTimeout; ///< the ssl connection timeout to use
     time_t startTime; ///< when the peer connector negotiation started
+    bool splice; ///< Whether we are going to splice or not
 
     CBDATA_CLASS2(PeerConnector);
 };
index d53ff29fd8d52f3b08ea9628c93bbfd5f87330b5..a9651e11ec3536983ad9f20f426b1abbe486a18b 100644 (file)
@@ -1093,9 +1093,9 @@ TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
 
 #if USE_OPENSSL
 void
-switchToTunnel(HttpRequest *request, int *status_ptr, Comm::ConnectionPointer &clientConn, Comm::ConnectionPointer &srvConn)
+switchToTunnel(HttpRequest *request, Comm::ConnectionPointer &clientConn, Comm::ConnectionPointer &srvConn)
 {
-    debugs(26, 3, HERE);
+    debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
     /* Create state structure. */
     TunnelStateData *tunnelState = NULL;
     const char *url = urlCanonical(request);
@@ -1108,7 +1108,10 @@ switchToTunnel(HttpRequest *request, int *status_ptr, Comm::ConnectionPointer &c
     tunnelState->url = xstrdup(url);
     tunnelState->request = request;
     tunnelState->server.size_ptr = NULL; //Set later if ClientSocketContext is available
-    tunnelState->status_ptr = status_ptr;
+
+    // Temporary static variable to store the unneeded for our case status code 
+    static int status_code = 0;
+    tunnelState->status_ptr = &status_code;
     tunnelState->client.conn = clientConn;
 
     ConnStateData *conn;