From: Amos Jeffries Date: Wed, 27 Jan 2016 16:56:38 +0000 (+1300) Subject: SourceLayout: shuffle PeerConnector classes to separate units X-Git-Tag: SQUID_4_0_5~22 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=32f1ca3f87f60e0fdbee2f5a8ea75184d32b247b;p=thirdparty%2Fsquid.git SourceLayout: shuffle PeerConnector classes to separate units --- diff --git a/src/FwdState.cc b/src/FwdState.cc index 143594915c..39a555661a 100644 --- a/src/FwdState.cc +++ b/src/FwdState.cc @@ -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 diff --git a/src/PeerPoolMgr.cc b/src/PeerPoolMgr.cc index 4c1be7621b..79f2dc43b3 100644 --- a/src/PeerPoolMgr.cc +++ b/src/PeerPoolMgr.cc @@ -22,11 +22,7 @@ #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 index 0000000000..02523304c6 --- /dev/null +++ b/src/ssl/BlindPeerConnector.cc @@ -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 index 0000000000..79f3881f24 --- /dev/null +++ b/src/ssl/BlindPeerConnector.h @@ -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 */ + diff --git a/src/ssl/Makefile.am b/src/ssl/Makefile.am index 0f9d8c8448..455828de1b 100644 --- a/src/ssl/Makefile.am +++ b/src/ssl/Makefile.am @@ -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 index 0000000000..912e6c27a4 --- /dev/null +++ b/src/ssl/PeekingPeerConnector.cc @@ -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(peerConnect), Ssl::PeekingPeerConnector, checkForPeekAndSpliceDone, answer); +} + +void +Ssl::PeekingPeerConnector::checkForPeekAndSpliceDone(allow_t answer) +{ + const Ssl::BumpMode finalAction = (answer.code == ACCESS_ALLOWED) ? + static_cast(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(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(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(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(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(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(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 index 0000000000..b851cc0f29 --- /dev/null +++ b/src/ssl/PeekingPeerConnector.h @@ -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 */ + diff --git a/src/ssl/PeerConnector.cc b/src/ssl/PeerConnector.cc index 05b8ba52fe..ceff1e8efb 100644 --- a/src/ssl/PeerConnector.cc +++ b/src/ssl/PeerConnector.cc @@ -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(peerConnect), Ssl::PeekingPeerConnector, checkForPeekAndSpliceDone, answer); -} - -void -Ssl::PeekingPeerConnector::checkForPeekAndSpliceDone(allow_t answer) -{ - const Ssl::BumpMode finalAction = (answer.code == ACCESS_ALLOWED) ? - static_cast(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(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(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(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(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(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(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/PeerConnector.h b/src/ssl/PeerConnector.h index c48321e8d4..3773b915fa 100644 --- a/src/ssl/PeerConnector.h +++ b/src/ssl/PeerConnector.h @@ -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" @@ -15,18 +15,17 @@ #include "CommCalls.h" #include "security/EncryptorAnswer.h" #include "ssl/support.h" + #include +#if USE_OPENSSL + class HttpRequest; class ErrorState; namespace Ssl { -class ErrorDetail; -class CertValidationResponse; -typedef RefCount 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 */ diff --git a/src/ssl/support.h b/src/ssl/support.h index 5df4d5b596..95da6b2cfb 100644 --- a/src/ssl/support.h +++ b/src/ssl/support.h @@ -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 Errors; +class ErrorDetail; +class CertValidationResponse; +typedef RefCount 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 */ diff --git a/src/tunnel.cc b/src/tunnel.cc index 2aae972b9a..319026ede0 100644 --- a/src/tunnel.cc +++ b/src/tunnel.cc @@ -35,12 +35,10 @@ #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