]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
SourceLayout: shuffle PeerConnector classes to separate units
authorAmos Jeffries <squid3@treenet.co.nz>
Wed, 27 Jan 2016 16:56:38 +0000 (05:56 +1300)
committerAmos Jeffries <squid3@treenet.co.nz>
Wed, 27 Jan 2016 16:56:38 +0000 (05:56 +1300)
src/FwdState.cc
src/PeerPoolMgr.cc
src/ssl/BlindPeerConnector.cc [new file with mode: 0644]
src/ssl/BlindPeerConnector.h [new file with mode: 0644]
src/ssl/Makefile.am
src/ssl/PeekingPeerConnector.cc [new file with mode: 0644]
src/ssl/PeekingPeerConnector.h [new file with mode: 0644]
src/ssl/PeerConnector.cc
src/ssl/PeerConnector.h
src/ssl/support.h
src/tunnel.cc

index 143594915c79886a8eaa128156c537375a072cf7..39a555661a89168f38069a0f0ae2c6716acfd24c 100644 (file)
@@ -46,6 +46,8 @@
 #include "PeerSelectState.h"
 #include "SquidConfig.h"
 #include "SquidTime.h"
+#include "ssl/BlindPeerConnector.h"
+#include "ssl/PeekingPeerConnector.h"
 #include "Store.h"
 #include "StoreClient.h"
 #include "urn.h"
@@ -55,7 +57,6 @@
 #include "ssl/Config.h"
 #include "ssl/ErrorDetail.h"
 #include "ssl/helper.h"
-#include "ssl/PeerConnector.h"
 #include "ssl/ServerBump.h"
 #include "ssl/support.h"
 #else
index 4c1be7621bb0e6b404af5e3261ff1a9680d5c59c..79f2dc43b3e6c7eaa57cd7af2ed069659b75d76e 100644 (file)
 #include "PeerPoolMgr.h"
 #include "SquidConfig.h"
 #include "SquidTime.h"
-#if USE_OPENSSL
-#include "ssl/PeerConnector.h"
-#else
-#include "security/EncryptorAnswer.h"
-#endif
+#include "ssl/BlindPeerConnector.h"
 
 CBDATA_CLASS_INIT(PeerPoolMgr);
 
diff --git a/src/ssl/BlindPeerConnector.cc b/src/ssl/BlindPeerConnector.cc
new file mode 100644 (file)
index 0000000..0252330
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "CachePeer.h"
+#include "comm/Connection.h"
+#include "fde.h"
+#include "HttpRequest.h"
+#include "neighbors.h"
+#include "security/NegotiationHistory.h"
+#include "SquidConfig.h"
+#include "ssl/BlindPeerConnector.h"
+
+CBDATA_NAMESPACED_CLASS_INIT(Ssl, BlindPeerConnector);
+
+Security::ContextPtr
+Ssl::BlindPeerConnector::getSslContext()
+{
+    if (const CachePeer *peer = serverConnection()->getPeer()) {
+        assert(peer->secure.encryptTransport);
+        Security::ContextPtr sslContext(peer->sslContext);
+        return sslContext;
+    }
+    return ::Config.ssl_client.sslContext;
+}
+
+Security::SessionPtr
+Ssl::BlindPeerConnector::initializeSsl()
+{
+    auto ssl = Ssl::PeerConnector::initializeSsl();
+    if (!ssl)
+        return nullptr;
+
+    if (const CachePeer *peer = serverConnection()->getPeer()) {
+        assert(peer);
+
+        // NP: domain may be a raw-IP but it is now always set
+        assert(!peer->secure.sslDomain.isEmpty());
+
+        // const loss is okay here, ssl_ex_index_server is only read and not assigned a destructor
+        SBuf *host = new SBuf(peer->secure.sslDomain);
+        SSL_set_ex_data(ssl, ssl_ex_index_server, host);
+
+        if (peer->sslSession)
+            SSL_set_session(ssl, peer->sslSession);
+    } else {
+        SBuf *hostName = new SBuf(request->url.host());
+        SSL_set_ex_data(ssl, ssl_ex_index_server, (void*)hostName);
+    }
+
+    return ssl;
+}
+
+void
+Ssl::BlindPeerConnector::noteNegotiationDone(ErrorState *error)
+{
+    if (error) {
+        // XXX: forward.cc calls peerConnectSucceeded() after an OK TCP connect but
+        // we call peerConnectFailed() if SSL failed afterwards. Is that OK?
+        // It is not clear whether we should call peerConnectSucceeded/Failed()
+        // based on TCP results, SSL results, or both. And the code is probably not
+        // consistent in this aspect across tunnelling and forwarding modules.
+        if (CachePeer *p = serverConnection()->getPeer())
+            peerConnectFailed(p);
+        return;
+    }
+
+    const int fd = serverConnection()->fd;
+    Security::SessionPtr ssl = fd_table[fd].ssl.get();
+    if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
+        if (serverConnection()->getPeer()->sslSession)
+            SSL_SESSION_free(serverConnection()->getPeer()->sslSession);
+
+        serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl);
+    }
+}
+
diff --git a/src/ssl/BlindPeerConnector.h b/src/ssl/BlindPeerConnector.h
new file mode 100644 (file)
index 0000000..79f3881
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SRC_SSL_BLINDPEERCONNECTOR_H
+#define SQUID_SRC_SSL_BLINDPEERCONNECTOR_H
+
+#include "ssl/PeerConnector.h"
+
+#if USE_OPENSSL
+
+namespace Ssl
+{
+
+/// A simple PeerConnector for SSL/TLS cache_peers. No SslBump capabilities.
+class BlindPeerConnector: public PeerConnector {
+    CBDATA_CLASS(BlindPeerConnector);
+public:
+    BlindPeerConnector(HttpRequestPointer &aRequest,
+                       const Comm::ConnectionPointer &aServerConn,
+                       AsyncCall::Pointer &aCallback, const time_t timeout = 0) :
+        AsyncJob("Ssl::BlindPeerConnector"),
+        PeerConnector(aServerConn, aCallback, timeout)
+    {
+        request = aRequest;
+    }
+
+    /* PeerConnector API */
+
+    /// Calls parent initializeSSL, configure the created SSL object to try reuse SSL session
+    /// and sets the hostname to use for certificates validation
+    virtual Security::SessionPtr initializeSsl();
+
+    /// Return the configured Security::ContextPtr object
+    virtual Security::ContextPtr getSslContext();
+
+    /// On error calls peerConnectFailed function, on success store the used SSL session
+    /// for later use
+    virtual void noteNegotiationDone(ErrorState *error);
+};
+
+} // namespace Ssl
+
+#endif /* USE_OPENSSL */
+#endif /* SQUID_SRC_SSL_BLINDPEERCONNECTOR_H */
+
index 0f9d8c8448dc4c515ce2ddc6b8da7d7e87449222..455828de1bd60debffc34c989b98eedae0201c3f 100644 (file)
@@ -27,6 +27,8 @@ endif
 libsslsquid_la_SOURCES = \
        bio.cc \
        bio.h \
+       BlindPeerConnector.cc \
+       BlindPeerConnector.h \
        cert_validate_message.cc \
        cert_validate_message.h \
        context_storage.cc \
@@ -37,6 +39,8 @@ libsslsquid_la_SOURCES = \
        ErrorDetail.h \
        ErrorDetailManager.cc \
        ErrorDetailManager.h \
+       PeekingPeerConnector.cc \
+       PeekingPeerConnector.h \
        PeerConnector.cc \
        PeerConnector.h \
        ProxyCerts.h \
diff --git a/src/ssl/PeekingPeerConnector.cc b/src/ssl/PeekingPeerConnector.cc
new file mode 100644 (file)
index 0000000..912e6c2
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+/* DEBUG: section 83    SSL-Bump Server/Peer negotiation */
+
+#include "squid.h"
+#include "acl/FilledChecklist.h"
+#include "client_side.h"
+#include "errorpage.h"
+#include "fde.h"
+#include "HttpRequest.h"
+#include "security/NegotiationHistory.h"
+#include "SquidConfig.h"
+#include "ssl/bio.h"
+#include "ssl/PeekingPeerConnector.h"
+#include "ssl/ServerBump.h"
+
+CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeekingPeerConnector);
+
+void switchToTunnel(HttpRequest *request, Comm::ConnectionPointer & clientConn, Comm::ConnectionPointer &srvConn);
+
+void
+Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone(allow_t answer, void *data)
+{
+    Ssl::PeekingPeerConnector *peerConnect = (Ssl::PeekingPeerConnector *) data;
+    // Use job calls to add done() checks and other job logic/protections.
+    CallJobHere1(83, 7, CbcPointer<PeekingPeerConnector>(peerConnect), Ssl::PeekingPeerConnector, checkForPeekAndSpliceDone, answer);
+}
+
+void
+Ssl::PeekingPeerConnector::checkForPeekAndSpliceDone(allow_t answer)
+{
+    const Ssl::BumpMode finalAction = (answer.code == ACCESS_ALLOWED) ?
+                                      static_cast<Ssl::BumpMode>(answer.kind):
+                                      checkForPeekAndSpliceGuess();
+    checkForPeekAndSpliceMatched(finalAction);
+}
+
+void
+Ssl::PeekingPeerConnector::checkForPeekAndSplice()
+{
+    // Mark Step3 of bumping
+    if (request->clientConnectionManager.valid()) {
+        if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
+            serverBump->step = Ssl::bumpStep3;
+        }
+    }
+
+    handleServerCertificate();
+
+    ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(
+        ::Config.accessList.ssl_bump,
+        request.getRaw(), NULL);
+    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpNone));
+    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpPeek));
+    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpStare));
+    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpClientFirst));
+    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpServerFirst));
+    Security::SessionPtr ssl = fd_table[serverConn->fd].ssl.get();
+    BIO *b = SSL_get_rbio(ssl);
+    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
+    if (!srvBio->canSplice())
+        acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpSplice));
+    if (!srvBio->canBump())
+        acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpBump));
+    acl_checklist->nonBlockingCheck(Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone, this);
+}
+
+void
+Ssl::PeekingPeerConnector::checkForPeekAndSpliceMatched(const Ssl::BumpMode action)
+{
+    Security::SessionPtr ssl = fd_table[serverConn->fd].ssl.get();
+    BIO *b = SSL_get_rbio(ssl);
+    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
+    debugs(83,5, "Will check for peek and splice on FD " << serverConn->fd);
+
+    Ssl::BumpMode finalAction = action;
+    Must(finalAction == Ssl::bumpSplice || finalAction == Ssl::bumpBump || finalAction == Ssl::bumpTerminate);
+    // Record final decision
+    if (request->clientConnectionManager.valid()) {
+        request->clientConnectionManager->sslBumpMode = finalAction;
+        request->clientConnectionManager->serverBump()->act.step3 = finalAction;
+    }
+
+    if (finalAction == Ssl::bumpTerminate) {
+        serverConn->close();
+        clientConn->close();
+    } else if (finalAction != Ssl::bumpSplice) {
+        //Allow write, proceed with the connection
+        srvBio->holdWrite(false);
+        srvBio->recordInput(false);
+        debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn->fd);
+        Ssl::PeerConnector::noteWantWrite();
+    } else {
+        splice = true;
+        // Ssl Negotiation stops here. Last SSL checks for valid certificates
+        // and if done, switch to tunnel mode
+        if (sslFinalized()) {
+            debugs(83,5, "Abort NegotiateSSL on FD " << serverConn->fd << " and splice the connection");
+        }
+    }
+}
+
+Ssl::BumpMode
+Ssl::PeekingPeerConnector::checkForPeekAndSpliceGuess() const
+{
+    if (const ConnStateData *csd = request->clientConnectionManager.valid()) {
+        const Ssl::BumpMode currentMode = csd->sslBumpMode;
+        if (currentMode == Ssl::bumpStare) {
+            debugs(83,5, "default to bumping after staring");
+            return Ssl::bumpBump;
+        }
+        debugs(83,5, "default to splicing after " << currentMode);
+    } else {
+        debugs(83,3, "default to splicing due to missing info");
+    }
+
+    return Ssl::bumpSplice;
+}
+
+Security::ContextPtr
+Ssl::PeekingPeerConnector::getSslContext()
+{
+    // XXX: locate a per-server context in Security:: instead
+    return ::Config.ssl_client.sslContext;
+}
+
+Security::SessionPtr
+Ssl::PeekingPeerConnector::initializeSsl()
+{
+    auto ssl = Ssl::PeerConnector::initializeSsl();
+    if (!ssl)
+        return nullptr;
+
+    if (ConnStateData *csd = request->clientConnectionManager.valid()) {
+
+        // client connection is required in the case we need to splice
+        // or terminate client and server connections
+        assert(clientConn != NULL);
+        SBuf *hostName = NULL;
+        Ssl::ClientBio *cltBio = NULL;
+
+        //Enable Status_request tls extension, required to bump some clients
+        SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
+
+        // In server-first bumping mode, clientSsl is NULL.
+        if (auto clientSsl = fd_table[clientConn->fd].ssl.get()) {
+            BIO *b = SSL_get_rbio(clientSsl);
+            cltBio = static_cast<Ssl::ClientBio *>(b->ptr);
+            const Ssl::Bio::sslFeatures &features = cltBio->receivedHelloFeatures();
+            if (!features.serverName.isEmpty())
+                hostName = new SBuf(features.serverName);
+        }
+
+        if (!hostName) {
+            // While we are peeking at the certificate, we may not know the server
+            // name that the client will request (after interception or CONNECT)
+            // unless it was the CONNECT request with a user-typed address.
+            const bool isConnectRequest = !csd->port->flags.isIntercepted();
+            if (!request->flags.sslPeek || isConnectRequest)
+                hostName = new SBuf(request->url.host());
+        }
+
+        if (hostName)
+            SSL_set_ex_data(ssl, ssl_ex_index_server, (void*)hostName);
+
+        Must(!csd->serverBump() || csd->serverBump()->step <= Ssl::bumpStep2);
+        if (csd->sslBumpMode == Ssl::bumpPeek || csd->sslBumpMode == Ssl::bumpStare) {
+            assert(cltBio);
+            const Ssl::Bio::sslFeatures &features = cltBio->receivedHelloFeatures();
+            if (features.sslVersion != -1) {
+                features.applyToSSL(ssl, csd->sslBumpMode);
+                // Should we allow it for all protocols?
+                if (features.sslVersion >= 3) {
+                    BIO *b = SSL_get_rbio(ssl);
+                    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
+                    // Inherite client features, like SSL version, SNI and other
+                    srvBio->setClientFeatures(features);
+                    srvBio->recordInput(true);
+                    srvBio->mode(csd->sslBumpMode);
+                }
+            }
+        } else {
+            // Set client SSL options
+            SSL_set_options(ssl, ::Security::ProxyOutgoingConfig.parsedOptions);
+
+            // Use SNI TLS extension only when we connect directly
+            // to the origin server and we know the server host name.
+            const char *sniServer = NULL;
+            const bool redirected = request->flags.redirected && ::Config.onoff.redir_rewrites_host;
+            if (!hostName || redirected)
+                sniServer = !request->url.hostIsNumeric() ? request->url.host() : NULL;
+            else
+                sniServer = hostName->c_str();
+
+            if (sniServer)
+                Ssl::setClientSNI(ssl, sniServer);
+        }
+
+        // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
+        X509 *peeked_cert;
+        if (csd->serverBump() &&
+                (peeked_cert = csd->serverBump()->serverCert.get())) {
+            CRYPTO_add(&(peeked_cert->references),1,CRYPTO_LOCK_X509);
+            SSL_set_ex_data(ssl, ssl_ex_index_ssl_peeked_cert, peeked_cert);
+        }
+    }
+
+    return ssl;
+}
+
+void
+Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState *error)
+{
+    Security::SessionPtr ssl = fd_table[serverConnection()->fd].ssl.get();
+
+    // Check the list error with
+    if (!request->clientConnectionManager.valid() || ! ssl)
+        return;
+
+    // remember the server certificate from the ErrorDetail object
+    if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
+        // remember validation errors, if any
+        if (certErrors) {
+            if (serverBump->sslErrors)
+                cbdataReferenceDone(serverBump->sslErrors);
+            serverBump->sslErrors = cbdataReference(certErrors);
+        }
+
+        if (!serverBump->serverCert.get()) {
+            // remember the server certificate from the ErrorDetail object
+            if (error && error->detail && error->detail->peerCert())
+                serverBump->serverCert.resetAndLock(error->detail->peerCert());
+            else {
+                handleServerCertificate();
+            }
+        }
+
+        if (error) {
+            // For intercepted connections, set the host name to the server
+            // certificate CN. Otherwise, we just hope that CONNECT is using
+            // a user-entered address (a host name or a user-entered IP).
+            const bool isConnectRequest = !request->clientConnectionManager->port->flags.isIntercepted();
+            if (request->flags.sslPeek && !isConnectRequest) {
+                if (X509 *srvX509 = serverBump->serverCert.get()) {
+                    if (const char *name = Ssl::CommonHostName(srvX509)) {
+                        request->url.host(name);
+                        debugs(83, 3, "reset request host: " << name);
+                    }
+                }
+            }
+        }
+    }
+
+    // retrieve TLS server information if any
+    serverConnection()->tlsNegotiations()->fillWith(ssl);
+    if (!error) {
+        serverCertificateVerified();
+        if (splice) {
+            //retrieved received TLS client informations
+            auto clientSsl = fd_table[clientConn->fd].ssl.get();
+            clientConn->tlsNegotiations()->fillWith(clientSsl);
+            switchToTunnel(request.getRaw(), clientConn, serverConn);
+        }
+    }
+}
+
+void
+Ssl::PeekingPeerConnector::noteWantWrite()
+{
+    const int fd = serverConnection()->fd;
+    Security::SessionPtr ssl = fd_table[fd].ssl.get();
+    BIO *b = SSL_get_rbio(ssl);
+    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
+
+    if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
+        debugs(81, DBG_IMPORTANT, "hold write on SSL connection on FD " << fd);
+        checkForPeekAndSplice();
+        return;
+    }
+
+    Ssl::PeerConnector::noteWantWrite();
+}
+
+void
+Ssl::PeekingPeerConnector::noteSslNegotiationError(const int result, const int ssl_error, const int ssl_lib_error)
+{
+    const int fd = serverConnection()->fd;
+    Security::SessionPtr ssl = fd_table[fd].ssl.get();
+    BIO *b = SSL_get_rbio(ssl);
+    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
+
+    // In Peek mode, the ClientHello message sent to the server. If the
+    // server resuming a previous (spliced) SSL session with the client,
+    // then probably we are here because local SSL object does not know
+    // anything about the session being resumed.
+    //
+    if (srvBio->bumpMode() == Ssl::bumpPeek && (resumingSession = srvBio->resumingSession())) {
+        // we currently splice all resumed sessions unconditionally
+        if (const bool spliceResumed = true) {
+            bypassCertValidator();
+            checkForPeekAndSpliceMatched(Ssl::bumpSplice);
+            return;
+        } // else fall through to find a matching ssl_bump action (with limited info)
+    }
+
+    // If we are in peek-and-splice mode and still we did not write to
+    // server yet, try to see if we should splice.
+    // In this case the connection can be saved.
+    // If the checklist decision is do not splice a new error will
+    // occur in the next SSL_connect call, and we will fail again.
+    // Abort on certificate validation errors to avoid splicing and
+    // thus hiding them.
+    // Abort if no certificate found probably because of malformed or
+    // unsupported server Hello message (TODO: make configurable).
+    if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) &&
+            (srvBio->bumpMode() == Ssl::bumpPeek  || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
+        Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
+        if (serverCert.get()) {
+            debugs(81, 3, "Error ("  << ERR_error_string(ssl_lib_error, NULL) <<  ") but, hold write on SSL connection on FD " << fd);
+            checkForPeekAndSplice();
+            return;
+        }
+    }
+
+    // else call parent noteNegotiationError to produce an error page
+    Ssl::PeerConnector::noteSslNegotiationError(result, ssl_error, ssl_lib_error);
+}
+
+void
+Ssl::PeekingPeerConnector::handleServerCertificate()
+{
+    if (serverCertificateHandled)
+        return;
+
+    if (ConnStateData *csd = request->clientConnectionManager.valid()) {
+        const int fd = serverConnection()->fd;
+        Security::SessionPtr ssl = fd_table[fd].ssl.get();
+        Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
+        if (!serverCert.get())
+            return;
+
+        serverCertificateHandled = true;
+
+        // remember the server certificate for later use
+        if (Ssl::ServerBump *serverBump = csd->serverBump()) {
+            serverBump->serverCert.reset(serverCert.release());
+        }
+    }
+}
+
+void
+Ssl::PeekingPeerConnector::serverCertificateVerified()
+{
+    if (ConnStateData *csd = request->clientConnectionManager.valid()) {
+        Security::CertPointer serverCert;
+        if(Ssl::ServerBump *serverBump = csd->serverBump())
+            serverCert.resetAndLock(serverBump->serverCert.get());
+        else {
+            const int fd = serverConnection()->fd;
+            Security::SessionPtr ssl = fd_table[fd].ssl.get();
+            serverCert.reset(SSL_get_peer_certificate(ssl));
+        }
+        if (serverCert.get()) {
+            csd->resetSslCommonName(Ssl::CommonHostName(serverCert.get()));
+            debugs(83, 5, "HTTPS server CN: " << csd->sslCommonName() <<
+                   " bumped: " << *serverConnection());
+        }
+    }
+}
+
diff --git a/src/ssl/PeekingPeerConnector.h b/src/ssl/PeekingPeerConnector.h
new file mode 100644 (file)
index 0000000..b851cc0
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SRC_SSL_PEEKINGPEERCONNECTOR_H
+#define SQUID_SRC_SSL_PEEKINGPEERCONNECTOR_H
+
+#include "ssl/PeerConnector.h"
+
+#if USE_OPENSSL
+
+namespace Ssl
+{
+
+/// A PeerConnector for HTTP origin servers. Capable of SslBumping.
+class PeekingPeerConnector: public PeerConnector {
+    CBDATA_CLASS(PeekingPeerConnector);
+public:
+    PeekingPeerConnector(HttpRequestPointer &aRequest,
+                         const Comm::ConnectionPointer &aServerConn,
+                         const Comm::ConnectionPointer &aClientConn,
+                         AsyncCall::Pointer &aCallback, const time_t timeout = 0) :
+        AsyncJob("Ssl::PeekingPeerConnector"),
+        PeerConnector(aServerConn, aCallback, timeout),
+        clientConn(aClientConn),
+        splice(false),
+        resumingSession(false),
+        serverCertificateHandled(false)
+    {
+        request = aRequest;
+    }
+
+    /* PeerConnector API */
+    virtual Security::SessionPtr initializeSsl();
+    virtual Security::ContextPtr getSslContext();
+    virtual void noteWantWrite();
+    virtual void noteSslNegotiationError(const int result, const int ssl_error, const int ssl_lib_error);
+    virtual void noteNegotiationDone(ErrorState *error);
+
+    /// Updates associated client connection manager members
+    /// if the server certificate was received from the server.
+    void handleServerCertificate();
+
+    /// Initiates the ssl_bump acl check in step3 SSL bump step to decide
+    /// about bumping, splicing or terminating the connection.
+    void checkForPeekAndSplice();
+
+    /// Callback function for ssl_bump acl check in step3  SSL bump step.
+    void checkForPeekAndSpliceDone(allow_t answer);
+
+    /// Handles the final bumping decision.
+    void checkForPeekAndSpliceMatched(const Ssl::BumpMode finalMode);
+
+    /// Guesses the final bumping decision when no ssl_bump rules match.
+    Ssl::BumpMode checkForPeekAndSpliceGuess() const;
+
+    /// Runs after the server certificate verified to update client
+    /// connection manager members
+    void serverCertificateVerified();
+
+    /// A wrapper function for checkForPeekAndSpliceDone for use with acl
+    static void cbCheckForPeekAndSpliceDone(allow_t answer, void *data);
+
+private:
+    Comm::ConnectionPointer clientConn; ///< TCP connection to the client
+    AsyncCall::Pointer callback; ///< we call this with the results
+    AsyncCall::Pointer closeHandler; ///< we call this when the connection closed
+    bool splice; ///< whether we are going to splice or not
+    bool resumingSession; ///< whether it is an SSL resuming session connection
+    bool serverCertificateHandled; ///< whether handleServerCertificate() succeeded
+};
+
+} // namespace Ssl
+
+#endif /* USE_OPENSSL */
+#endif /* SQUID_SRC_SSL_PEEKINGPEERCONNECTOR_H */
+
index 05b8ba52fe2bd4a5abdf1023e2a0881e29d70843..ceff1e8efb0cf53c69d767d9c5e4f586f079ea34 100644 (file)
@@ -6,34 +6,21 @@
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
-/* DEBUG: section 17    Request Forwarding */
+/* DEBUG: section 83    TLS Server/Peer negotiation */
 
 #include "squid.h"
 #include "acl/FilledChecklist.h"
-#include "base/AsyncCbdataCalls.h"
-#include "CachePeer.h"
-#include "client_side.h"
 #include "comm/Loops.h"
 #include "errorpage.h"
 #include "fde.h"
-#include "globals.h"
-#include "helper/ResultCode.h"
 #include "HttpRequest.h"
-#include "neighbors.h"
-#include "security/NegotiationHistory.h"
 #include "SquidConfig.h"
-#include "ssl/bio.h"
 #include "ssl/cert_validate_message.h"
 #include "ssl/Config.h"
-#include "ssl/ErrorDetail.h"
 #include "ssl/helper.h"
 #include "ssl/PeerConnector.h"
-#include "ssl/ServerBump.h"
-#include "ssl/support.h"
 
 CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeerConnector);
-CBDATA_NAMESPACED_CLASS_INIT(Ssl, BlindPeerConnector);
-CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeekingPeerConnector);
 
 Ssl::PeerConnector::PeerConnector(const Comm::ConnectionPointer &aServerConn, AsyncCall::Pointer &aCallback, const time_t timeout) :
     AsyncJob("Ssl::PeerConnector"),
@@ -209,107 +196,6 @@ Ssl::PeerConnector::sslFinalized()
     return true;
 }
 
-void switchToTunnel(HttpRequest *request, Comm::ConnectionPointer & clientConn, Comm::ConnectionPointer &srvConn);
-
-void
-Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone(allow_t answer, void *data)
-{
-    Ssl::PeekingPeerConnector *peerConnect = (Ssl::PeekingPeerConnector *) data;
-    // Use job calls to add done() checks and other job logic/protections.
-    CallJobHere1(83, 7, CbcPointer<PeekingPeerConnector>(peerConnect), Ssl::PeekingPeerConnector, checkForPeekAndSpliceDone, answer);
-}
-
-void
-Ssl::PeekingPeerConnector::checkForPeekAndSpliceDone(allow_t answer)
-{
-    const Ssl::BumpMode finalAction = (answer.code == ACCESS_ALLOWED) ?
-                                      static_cast<Ssl::BumpMode>(answer.kind):
-                                      checkForPeekAndSpliceGuess();
-    checkForPeekAndSpliceMatched(finalAction);
-}
-
-void
-Ssl::PeekingPeerConnector::checkForPeekAndSplice()
-{
-    // Mark Step3 of bumping
-    if (request->clientConnectionManager.valid()) {
-        if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
-            serverBump->step = Ssl::bumpStep3;
-        }
-    }
-
-    handleServerCertificate();
-
-    ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(
-        ::Config.accessList.ssl_bump,
-        request.getRaw(), NULL);
-    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpNone));
-    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpPeek));
-    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpStare));
-    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpClientFirst));
-    acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpServerFirst));
-    Security::SessionPtr ssl = fd_table[serverConn->fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
-    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
-    if (!srvBio->canSplice())
-        acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpSplice));
-    if (!srvBio->canBump())
-        acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpBump));
-    acl_checklist->nonBlockingCheck(Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone, this);
-}
-
-void
-Ssl::PeekingPeerConnector::checkForPeekAndSpliceMatched(const Ssl::BumpMode action)
-{
-    Security::SessionPtr ssl = fd_table[serverConn->fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
-    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
-    debugs(83,5, "Will check for peek and splice on FD " << serverConn->fd);
-
-    Ssl::BumpMode finalAction = action;
-    Must(finalAction == Ssl::bumpSplice || finalAction == Ssl::bumpBump || finalAction == Ssl::bumpTerminate);
-    // Record final decision
-    if (request->clientConnectionManager.valid()) {
-        request->clientConnectionManager->sslBumpMode = finalAction;
-        request->clientConnectionManager->serverBump()->act.step3 = finalAction;
-    }
-
-    if (finalAction == Ssl::bumpTerminate) {
-        serverConn->close();
-        clientConn->close();
-    } else if (finalAction != Ssl::bumpSplice) {
-        //Allow write, proceed with the connection
-        srvBio->holdWrite(false);
-        srvBio->recordInput(false);
-        debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn->fd);
-        Ssl::PeerConnector::noteWantWrite();
-    } else {
-        splice = true;
-        // Ssl Negotiation stops here. Last SSL checks for valid certificates
-        // and if done, switch to tunnel mode
-        if (sslFinalized()) {
-            debugs(83,5, "Abort NegotiateSSL on FD " << serverConn->fd << " and splice the connection");
-        }
-    }
-}
-
-Ssl::BumpMode
-Ssl::PeekingPeerConnector::checkForPeekAndSpliceGuess() const
-{
-    if (const ConnStateData *csd = request->clientConnectionManager.valid()) {
-        const Ssl::BumpMode currentMode = csd->sslBumpMode;
-        if (currentMode == Ssl::bumpStare) {
-            debugs(83,5, "default to bumping after staring");
-            return Ssl::bumpBump;
-        }
-        debugs(83,5, "default to splicing after " << currentMode);
-    } else {
-        debugs(83,3, "default to splicing due to missing info");
-    }
-
-    return Ssl::bumpSplice;
-}
-
 void
 Ssl::PeerConnector::sslCrtvdHandleReply(Ssl::CertValidationResponse::Pointer validationResponse)
 {
@@ -586,316 +472,3 @@ Ssl::PeerConnector::status() const
     return buf.content();
 }
 
-Security::ContextPtr
-Ssl::BlindPeerConnector::getSslContext()
-{
-    if (const CachePeer *peer = serverConnection()->getPeer()) {
-        assert(peer->secure.encryptTransport);
-        Security::ContextPtr sslContext(peer->sslContext);
-        return sslContext;
-    }
-    return ::Config.ssl_client.sslContext;
-}
-
-Security::SessionPtr
-Ssl::BlindPeerConnector::initializeSsl()
-{
-    auto ssl = Ssl::PeerConnector::initializeSsl();
-    if (!ssl)
-        return nullptr;
-
-    if (const CachePeer *peer = serverConnection()->getPeer()) {
-        assert(peer);
-
-        // NP: domain may be a raw-IP but it is now always set
-        assert(!peer->secure.sslDomain.isEmpty());
-
-        // const loss is okay here, ssl_ex_index_server is only read and not assigned a destructor
-        SBuf *host = new SBuf(peer->secure.sslDomain);
-        SSL_set_ex_data(ssl, ssl_ex_index_server, host);
-
-        if (peer->sslSession)
-            SSL_set_session(ssl, peer->sslSession);
-    } else {
-        SBuf *hostName = new SBuf(request->url.host());
-        SSL_set_ex_data(ssl, ssl_ex_index_server, (void*)hostName);
-    }
-
-    return ssl;
-}
-
-void
-Ssl::BlindPeerConnector::noteNegotiationDone(ErrorState *error)
-{
-    if (error) {
-        // XXX: forward.cc calls peerConnectSucceeded() after an OK TCP connect but
-        // we call peerConnectFailed() if SSL failed afterwards. Is that OK?
-        // It is not clear whether we should call peerConnectSucceeded/Failed()
-        // based on TCP results, SSL results, or both. And the code is probably not
-        // consistent in this aspect across tunnelling and forwarding modules.
-        if (CachePeer *p = serverConnection()->getPeer())
-            peerConnectFailed(p);
-        return;
-    }
-
-    const int fd = serverConnection()->fd;
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
-        if (serverConnection()->getPeer()->sslSession)
-            SSL_SESSION_free(serverConnection()->getPeer()->sslSession);
-
-        serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl);
-    }
-}
-
-Security::ContextPtr
-Ssl::PeekingPeerConnector::getSslContext()
-{
-    // XXX: locate a per-server context in Security:: instead
-    return ::Config.ssl_client.sslContext;
-}
-
-Security::SessionPtr
-Ssl::PeekingPeerConnector::initializeSsl()
-{
-    auto ssl = Ssl::PeerConnector::initializeSsl();
-    if (!ssl)
-        return nullptr;
-
-    if (ConnStateData *csd = request->clientConnectionManager.valid()) {
-
-        // client connection is required in the case we need to splice
-        // or terminate client and server connections
-        assert(clientConn != NULL);
-        SBuf *hostName = NULL;
-        Ssl::ClientBio *cltBio = NULL;
-
-        //Enable Status_request tls extension, required to bump some clients
-        SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
-
-        // In server-first bumping mode, clientSsl is NULL.
-        if (auto clientSsl = fd_table[clientConn->fd].ssl.get()) {
-            BIO *b = SSL_get_rbio(clientSsl);
-            cltBio = static_cast<Ssl::ClientBio *>(b->ptr);
-            const Ssl::Bio::sslFeatures &features = cltBio->receivedHelloFeatures();
-            if (!features.serverName.isEmpty())
-                hostName = new SBuf(features.serverName);
-        }
-
-        if (!hostName) {
-            // While we are peeking at the certificate, we may not know the server
-            // name that the client will request (after interception or CONNECT)
-            // unless it was the CONNECT request with a user-typed address.
-            const bool isConnectRequest = !csd->port->flags.isIntercepted();
-            if (!request->flags.sslPeek || isConnectRequest)
-                hostName = new SBuf(request->url.host());
-        }
-
-        if (hostName)
-            SSL_set_ex_data(ssl, ssl_ex_index_server, (void*)hostName);
-
-        Must(!csd->serverBump() || csd->serverBump()->step <= Ssl::bumpStep2);
-        if (csd->sslBumpMode == Ssl::bumpPeek || csd->sslBumpMode == Ssl::bumpStare) {
-            assert(cltBio);
-            const Ssl::Bio::sslFeatures &features = cltBio->receivedHelloFeatures();
-            if (features.sslVersion != -1) {
-                features.applyToSSL(ssl, csd->sslBumpMode);
-                // Should we allow it for all protocols?
-                if (features.sslVersion >= 3) {
-                    BIO *b = SSL_get_rbio(ssl);
-                    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
-                    // Inherite client features, like SSL version, SNI and other
-                    srvBio->setClientFeatures(features);
-                    srvBio->recordInput(true);
-                    srvBio->mode(csd->sslBumpMode);
-                }
-            }
-        } else {
-            // Set client SSL options
-            SSL_set_options(ssl, ::Security::ProxyOutgoingConfig.parsedOptions);
-
-            // Use SNI TLS extension only when we connect directly
-            // to the origin server and we know the server host name.
-            const char *sniServer = NULL;
-            const bool redirected = request->flags.redirected && ::Config.onoff.redir_rewrites_host;
-            if (!hostName || redirected)
-                sniServer = !request->url.hostIsNumeric() ? request->url.host() : NULL;
-            else
-                sniServer = hostName->c_str();
-
-            if (sniServer)
-                Ssl::setClientSNI(ssl, sniServer);
-        }
-
-        // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
-        X509 *peeked_cert;
-        if (csd->serverBump() &&
-                (peeked_cert = csd->serverBump()->serverCert.get())) {
-            CRYPTO_add(&(peeked_cert->references),1,CRYPTO_LOCK_X509);
-            SSL_set_ex_data(ssl, ssl_ex_index_ssl_peeked_cert, peeked_cert);
-        }
-    }
-
-    return ssl;
-}
-
-void
-Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState *error)
-{
-    Security::SessionPtr ssl = fd_table[serverConnection()->fd].ssl.get();
-
-    // Check the list error with
-    if (!request->clientConnectionManager.valid() || ! ssl)
-        return;
-
-    // remember the server certificate from the ErrorDetail object
-    if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
-        // remember validation errors, if any
-        if (certErrors) {
-            if (serverBump->sslErrors)
-                cbdataReferenceDone(serverBump->sslErrors);
-            serverBump->sslErrors = cbdataReference(certErrors);
-        }
-
-        if (!serverBump->serverCert.get()) {
-            // remember the server certificate from the ErrorDetail object
-            if (error && error->detail && error->detail->peerCert())
-                serverBump->serverCert.resetAndLock(error->detail->peerCert());
-            else {
-                handleServerCertificate();
-            }
-        }
-
-        if (error) {
-            // For intercepted connections, set the host name to the server
-            // certificate CN. Otherwise, we just hope that CONNECT is using
-            // a user-entered address (a host name or a user-entered IP).
-            const bool isConnectRequest = !request->clientConnectionManager->port->flags.isIntercepted();
-            if (request->flags.sslPeek && !isConnectRequest) {
-                if (X509 *srvX509 = serverBump->serverCert.get()) {
-                    if (const char *name = Ssl::CommonHostName(srvX509)) {
-                        request->url.host(name);
-                        debugs(83, 3, "reset request host: " << name);
-                    }
-                }
-            }
-        }
-    }
-
-    // retrieve TLS server information if any
-    serverConnection()->tlsNegotiations()->fillWith(ssl);
-    if (!error) {
-        serverCertificateVerified();
-        if (splice) {
-            //retrieved received TLS client informations
-            auto clientSsl = fd_table[clientConn->fd].ssl.get();
-            clientConn->tlsNegotiations()->fillWith(clientSsl);
-            switchToTunnel(request.getRaw(), clientConn, serverConn);
-        }
-    }
-}
-
-void
-Ssl::PeekingPeerConnector::noteWantWrite()
-{
-    const int fd = serverConnection()->fd;
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
-    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
-
-    if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
-        debugs(81, DBG_IMPORTANT, "hold write on SSL connection on FD " << fd);
-        checkForPeekAndSplice();
-        return;
-    }
-
-    Ssl::PeerConnector::noteWantWrite();
-}
-
-void
-Ssl::PeekingPeerConnector::noteSslNegotiationError(const int result, const int ssl_error, const int ssl_lib_error)
-{
-    const int fd = serverConnection()->fd;
-    Security::SessionPtr ssl = fd_table[fd].ssl.get();
-    BIO *b = SSL_get_rbio(ssl);
-    Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
-
-    // In Peek mode, the ClientHello message sent to the server. If the
-    // server resuming a previous (spliced) SSL session with the client,
-    // then probably we are here because local SSL object does not know
-    // anything about the session being resumed.
-    //
-    if (srvBio->bumpMode() == Ssl::bumpPeek && (resumingSession = srvBio->resumingSession())) {
-        // we currently splice all resumed sessions unconditionally
-        if (const bool spliceResumed = true) {
-            bypassCertValidator();
-            checkForPeekAndSpliceMatched(Ssl::bumpSplice);
-            return;
-        } // else fall through to find a matching ssl_bump action (with limited info)
-    }
-
-    // If we are in peek-and-splice mode and still we did not write to
-    // server yet, try to see if we should splice.
-    // In this case the connection can be saved.
-    // If the checklist decision is do not splice a new error will
-    // occur in the next SSL_connect call, and we will fail again.
-    // Abort on certificate validation errors to avoid splicing and
-    // thus hiding them.
-    // Abort if no certificate found probably because of malformed or
-    // unsupported server Hello message (TODO: make configurable).
-    if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) &&
-            (srvBio->bumpMode() == Ssl::bumpPeek  || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
-        Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
-        if (serverCert.get()) {
-            debugs(81, 3, "Error ("  << ERR_error_string(ssl_lib_error, NULL) <<  ") but, hold write on SSL connection on FD " << fd);
-            checkForPeekAndSplice();
-            return;
-        }
-    }
-
-    // else call parent noteNegotiationError to produce an error page
-    Ssl::PeerConnector::noteSslNegotiationError(result, ssl_error, ssl_lib_error);
-}
-
-void
-Ssl::PeekingPeerConnector::handleServerCertificate()
-{
-    if (serverCertificateHandled)
-        return;
-
-    if (ConnStateData *csd = request->clientConnectionManager.valid()) {
-        const int fd = serverConnection()->fd;
-        Security::SessionPtr ssl = fd_table[fd].ssl.get();
-        Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
-        if (!serverCert.get())
-            return;
-
-        serverCertificateHandled = true;
-
-        // remember the server certificate for later use
-        if (Ssl::ServerBump *serverBump = csd->serverBump()) {
-            serverBump->serverCert.reset(serverCert.release());
-        }
-    }
-}
-
-void
-Ssl::PeekingPeerConnector::serverCertificateVerified()
-{
-    if (ConnStateData *csd = request->clientConnectionManager.valid()) {
-        Security::CertPointer serverCert;
-        if(Ssl::ServerBump *serverBump = csd->serverBump())
-            serverCert.resetAndLock(serverBump->serverCert.get());
-        else {
-            const int fd = serverConnection()->fd;
-            Security::SessionPtr ssl = fd_table[fd].ssl.get();
-            serverCert.reset(SSL_get_peer_certificate(ssl));
-        }
-        if (serverCert.get()) {
-            csd->resetSslCommonName(Ssl::CommonHostName(serverCert.get()));
-            debugs(83, 5, "HTTPS server CN: " << csd->sslCommonName() <<
-                   " bumped: " << *serverConnection());
-        }
-    }
-}
-
index c48321e8d48b70a22bfa109cb1db6225e5fbed12..3773b915fae255a03e75ae64f449b4725655a5f6 100644 (file)
@@ -6,8 +6,8 @@
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
-#ifndef SQUID_SSL_PEER_CONNECTOR_H
-#define SQUID_SSL_PEER_CONNECTOR_H
+#ifndef SQUID_SRC_SSL_PEERCONNECTOR_H
+#define SQUID_SRC_SSL_PEERCONNECTOR_H
 
 #include "acl/Acl.h"
 #include "base/AsyncCbdataCalls.h"
 #include "CommCalls.h"
 #include "security/EncryptorAnswer.h"
 #include "ssl/support.h"
+
 #include <iosfwd>
 
+#if USE_OPENSSL
+
 class HttpRequest;
 class ErrorState;
 
 namespace Ssl
 {
 
-class ErrorDetail;
-class CertValidationResponse;
-typedef RefCount<CertValidationResponse> CertValidationResponsePointer;
-
 /**
  \par
  * Connects Squid to SSL/TLS-capable peers or services.
@@ -176,92 +175,8 @@ private:
     bool useCertValidator_; ///< whether the certificate validator should bypassed
 };
 
-/// A simple PeerConnector for SSL/TLS cache_peers. No SslBump capabilities.
-class BlindPeerConnector: public PeerConnector {
-    CBDATA_CLASS(BlindPeerConnector);
-public:
-    BlindPeerConnector(HttpRequestPointer &aRequest,
-                       const Comm::ConnectionPointer &aServerConn,
-                       AsyncCall::Pointer &aCallback, const time_t timeout = 0) :
-        AsyncJob("Ssl::BlindPeerConnector"),
-        PeerConnector(aServerConn, aCallback, timeout)
-    {
-        request = aRequest;
-    }
-
-    /* PeerConnector API */
-
-    /// Calls parent initializeSSL, configure the created SSL object to try reuse SSL session
-    /// and sets the hostname to use for certificates validation
-    virtual Security::SessionPtr initializeSsl();
-
-    /// Return the configured Security::ContextPtr object
-    virtual Security::ContextPtr getSslContext();
-
-    /// On error calls peerConnectFailed function, on success store the used SSL session
-    /// for later use
-    virtual void noteNegotiationDone(ErrorState *error);
-};
-
-/// A PeerConnector for HTTP origin servers. Capable of SslBumping.
-class PeekingPeerConnector: public PeerConnector {
-    CBDATA_CLASS(PeekingPeerConnector);
-public:
-    PeekingPeerConnector(HttpRequestPointer &aRequest,
-                         const Comm::ConnectionPointer &aServerConn,
-                         const Comm::ConnectionPointer &aClientConn,
-                         AsyncCall::Pointer &aCallback, const time_t timeout = 0) :
-        AsyncJob("Ssl::PeekingPeerConnector"),
-        PeerConnector(aServerConn, aCallback, timeout),
-        clientConn(aClientConn),
-        splice(false),
-        resumingSession(false),
-        serverCertificateHandled(false)
-    {
-        request = aRequest;
-    }
-
-    /* PeerConnector API */
-    virtual Security::SessionPtr initializeSsl();
-    virtual Security::ContextPtr getSslContext();
-    virtual void noteWantWrite();
-    virtual void noteSslNegotiationError(const int result, const int ssl_error, const int ssl_lib_error);
-    virtual void noteNegotiationDone(ErrorState *error);
-
-    /// Updates associated client connection manager members
-    /// if the server certificate was received from the server.
-    void handleServerCertificate();
-
-    /// Initiates the ssl_bump acl check in step3 SSL bump step to decide
-    /// about bumping, splicing or terminating the connection.
-    void checkForPeekAndSplice();
-
-    /// Callback function for ssl_bump acl check in step3  SSL bump step.
-    void checkForPeekAndSpliceDone(allow_t answer);
-
-    /// Handles the final bumping decision.
-    void checkForPeekAndSpliceMatched(const Ssl::BumpMode finalMode);
-
-    /// Guesses the final bumping decision when no ssl_bump rules match.
-    Ssl::BumpMode checkForPeekAndSpliceGuess() const;
-
-    /// Runs after the server certificate verified to update client
-    /// connection manager members
-    void serverCertificateVerified();
-
-    /// A wrapper function for checkForPeekAndSpliceDone for use with acl
-    static void cbCheckForPeekAndSpliceDone(allow_t answer, void *data);
-
-private:
-    Comm::ConnectionPointer clientConn; ///< TCP connection to the client
-    AsyncCall::Pointer callback; ///< we call this with the results
-    AsyncCall::Pointer closeHandler; ///< we call this when the connection closed
-    bool splice; ///< whether we are going to splice or not
-    bool resumingSession; ///< whether it is an SSL resuming session connection
-    bool serverCertificateHandled; ///< whether handleServerCertificate() succeeded
-};
-
 } // namespace Ssl
 
-#endif /* SQUID_PEER_CONNECTOR_H */
+#endif /* USE_OPENSSL */
+#endif /* SQUID_SRC_SSL_PEERCONNECTOR_H */
 
index 5df4d5b5966a16924006bcfb6ab0ec604690eccd..95da6b2cfb3c83e07bd380815f406d174018f4a9 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef SQUID_SSL_SUPPORT_H
 #define SQUID_SSL_SUPPORT_H
 
+#if USE_OPENSSL
+
 #include "base/CbDataList.h"
 #include "SBuf.h"
 #include "security/forward.h"
@@ -65,6 +67,10 @@ typedef int ssl_error_t;
 
 typedef CbDataList<Ssl::ssl_error_t> Errors;
 
+class ErrorDetail;
+class CertValidationResponse;
+typedef RefCount<CertValidationResponse> CertValidationResponsePointer;
+
 /// Creates SSL Client connection structure and initializes SSL I/O (Comm and BIO).
 /// On errors, emits DBG_IMPORTANT with details and returns NULL.
 SSL *CreateClient(Security::ContextPtr sslContext, const int fd, const char *squidCtx);
@@ -341,5 +347,6 @@ int SSL_set_fd(SSL *ssl, int fd)
 
 #endif /* _SQUID_WINDOWS_ */
 
+#endif /* USE_OPENSSL */
 #endif /* SQUID_SSL_SUPPORT_H */
 
index 2aae972b9a5f443ec8e4a06dc266b40a4a9b3dfc..319026ede0d8b2fa495772a757ccc7f2fa47842f 100644 (file)
 #include "SquidConfig.h"
 #include "SquidTime.h"
 #include "StatCounters.h"
+#include "ssl/BlindPeerConnector.h"
 #if USE_OPENSSL
 #include "ssl/bio.h"
-#include "ssl/PeerConnector.h"
 #include "ssl/ServerBump.h"
-#else
-#include "security/EncryptorAnswer.h"
 #endif
 #include "tools.h"
 #if USE_DELAY_POOLS