From: Christos Tsantilas Date: Mon, 6 Oct 2014 14:53:40 +0000 (+0300) Subject: Validate server certificates without bumping X-Git-Tag: SQUID_3_5_0_1~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c91d4d4e713e0a8ecb05609adcaaa745766c4d5e;p=thirdparty%2Fsquid.git Validate server certificates without bumping 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 --- diff --git a/src/ssl/PeerConnector.cc b/src/ssl/PeerConnector.cc index c618de25be..607d881a97 100644 --- a/src/ssl/PeerConnector.cc +++ b/src/ssl/PeerConnector.cc @@ -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(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; } diff --git a/src/ssl/PeerConnector.h b/src/ssl/PeerConnector.h index 7f9e680621..1f453cdaf6 100644 --- a/src/ssl/PeerConnector.h +++ b/src/ssl/PeerConnector.h @@ -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); }; diff --git a/src/tunnel.cc b/src/tunnel.cc index d53ff29fd8..a9651e11ec 100644 --- a/src/tunnel.cc +++ b/src/tunnel.cc @@ -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;