------------------------------------------------------------ revno: 13629 revision-id: chtsanti@users.sourceforge.net-20141006145340-2qhahfh6v5f5yo5b parent: squid3@treenet.co.nz-20141005152650-k62ltcdh63x13z55 committer: Christos Tsantilas branch nick: trunk timestamp: Mon 2014-10-06 17:53:40 +0300 message: 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 ------------------------------------------------------------ # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: chtsanti@users.sourceforge.net-20141006145340-\ # 2qhahfh6v5f5yo5b # target_branch: http://bzr.squid-cache.org/bzr/squid3/trunk/ # testament_sha1: f79593207e904940b5d63b56b0d8919597d47807 # timestamp: 2014-10-06 17:35:42 +0000 # source_branch: http://bzr.squid-cache.org/bzr/squid3/trunk # base_revision_id: squid3@treenet.co.nz-20141005152650-\ # k62ltcdh63x13z55 # # Begin patch === modified file 'src/ssl/PeerConnector.cc' --- src/ssl/PeerConnector.cc 2014-10-01 12:46:44 +0000 +++ src/ssl/PeerConnector.cc 2014-10-06 14:53:40 +0000 @@ -44,7 +44,8 @@ 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,17 +231,6 @@ return; // we might be gone by now } - if (request->clientConnectionManager.valid()) { - // remember the server certificate from the ErrorDetail object - if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) { - serverBump->serverCert.reset(SSL_get_peer_certificate(ssl)); - - // remember validation errors, if any - if (Ssl::CertErrors *errs = static_cast(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors))) - serverBump->sslErrors = cbdataReference(errs); - } - } - if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) { if (serverConnection()->getPeer()->sslSession) SSL_SESSION_free(serverConnection()->getPeer()->sslSession); @@ -248,6 +238,29 @@ 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()) { + serverBump->serverCert.reset(SSL_get_peer_certificate(ssl)); + + // remember validation errors, if any + if (Ssl::CertErrors *errs = static_cast(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors))) + serverBump->sslErrors = cbdataReference(errs); + } + } + 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 @@ 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 @@ 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 @@ 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 @@ validatorFailed = true; if (!errDetails && !validatorFailed) { - callBack(); + if (splice) + switchToTunnel(request.getRaw(), clientConn, serverConn); + else + callBack(); return; } === modified file 'src/ssl/PeerConnector.h' --- src/ssl/PeerConnector.h 2014-10-01 12:31:58 +0000 +++ src/ssl/PeerConnector.h 2014-10-06 14:53:40 +0000 @@ -116,6 +116,11 @@ /// 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 @@ 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); }; === modified file 'src/tunnel.cc' --- src/tunnel.cc 2014-09-13 13:59:43 +0000 +++ src/tunnel.cc 2014-10-06 14:53:40 +0000 @@ -1093,9 +1093,9 @@ #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 @@ 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;