#include "errorpage.h"
#include "eui/Config.h"
#include "fde.h"
+#include "forward.h"
#include "HttpHdrContRange.h"
#include "HttpReply.h"
#include "HttpRequest.h"
#if USE_SSL
#include "ssl/context_storage.h"
#include "ssl/helper.h"
-#include "ssl/ServerPeeker.h"
+#include "ssl/ServerBump.h"
#include "ssl/support.h"
#include "ssl/gadgets.h"
#endif
if (bodyPipe != NULL)
stopProducingFor(bodyPipe, false);
-#if USE_SSL
- if (bumpErrorEntry)
- bumpErrorEntry->unlock();
-
- cbdataReferenceDone(bumpSslErrorNoList);
+#if USE_SSL
+ delete sslServerBump;
#endif
}
bool ConnStateData::serveDelayedError(ClientSocketContext *context)
{
ClientHttpRequest *http = context->http;
- StoreEntry *e = bumpServerFirstErrorEntry();
- if (!e)
+
+ if (!sslServerBump)
return false;
- if (!e->isEmpty()) {
+ assert(sslServerBump->entry);
+ if (!sslServerBump->entry->isEmpty()) {
quitAfterError(http->request);
//Failed? Here we should get the error from conn and send it to client
clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
assert (repContext);
debugs(33, 5, "Connection first has failed for " << http->uri << ". Respond with an error");
- repContext->setReplyToStoreEntry(e);
+ repContext->setReplyToStoreEntry(sslServerBump->entry);
context->pullData();
return true;
}
// We are in ssl-bump first mode. We have not the server connect name when
// we connected to server so we have to check certificates subject with our server name
- if (X509 *server_cert = getBumpServerCert()) {
+ if (sslServerBump && sslServerBump->serverCert.get()) {
HttpRequest *request = http->request;
- if (!Ssl::checkX509ServerValidity(server_cert, request->GetHost())) {
+ if (!Ssl::checkX509ServerValidity(sslServerBump->serverCert.get(), request->GetHost())) {
debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate does not match domainname " << request->GetHost());
ACLFilledChecklist check(Config.ssl_client.cert_error, request, dash_str);
assert (repContext);
// Fill the server ip address and server hostname for use with ErrorState
- request->hier.note(pinning.serverConnection, request->GetHost());
+ HttpRequest::Pointer const & peekerRequest = sslServerBump->request;
+ request->hier.note(peekerRequest->hier.tcpServer, request->GetHost());
// Create an error object and fill it
ErrorState *err = new ErrorState(ERR_SECURE_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
#else
err->xerrno = EACCES;
#endif
- Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail( SQUID_X509_V_ERR_DOMAIN_MISMATCH, server_cert, NULL);
+ Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail( SQUID_X509_V_ERR_DOMAIN_MISMATCH, sslServerBump->serverCert.get(), NULL);
err->detail = errDetail;
repContext->setReplyToError(request->method, err);
assert(context->http->out.offset == 0);
certProperties.commonName = sslCommonName.defined() ? sslCommonName.termedBuf() : sslConnectHostOrIp.termedBuf();
// fake certificate adaptation requires bump-server-first mode
- if (!bumpServerFirstErrorEntry())
+ if (!sslServerBump)
return;
// In the case of error while connecting to secure server, use a fake trusted certificate,
// with no mimicked fields and no adaptation algorithms
- if (bumpServerFirstErrorEntry()->isEmpty()) {
- if (X509 *mimicCert = bumpServerCert.get())
+ assert(sslServerBump->entry);
+ if (sslServerBump->entry->isEmpty()) {
+ if (X509 *mimicCert = sslServerBump->serverCert.get())
certProperties.mimicCert.resetAndLock(mimicCert);
HttpRequest *fakeRequest = new HttpRequest();
checklist.conn(this);
checklist.src_addr = clientConnection->remote;
checklist.my_addr = clientConnection->local;
- checklist.sslErrorList = cbdataReference(bumpSslErrorNoList);
+ checklist.sslErrorList = cbdataReference(sslServerBump->bumpSslErrorNoList);
for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != NULL; ca = ca->next) {
if (ca->aclList && checklist.fastCheck(ca->aclList) == ACCESS_ALLOWED) {
break;
}
}
- } else {// if (!bumpServerFirstErrorEntry()->isEmpty())
+ } else {// if (!sslServerBump->entry->isEmpty())
// Use trusted certificate for a Squid-generated error
// or the user would have to add a security exception
// just to see the error page. We will close the connection
const bool alwaysBumpServerFirst = true;
if (alwaysBumpServerFirst) {
- Must(!httpsPeeker.set());
- httpsPeeker = new Ssl::ServerPeeker(this, sslConnectHostOrIp.termedBuf(), port);
- bumpErrorEntry = httpsPeeker->storeEntry();
- Must(bumpErrorEntry);
- bumpErrorEntry->lock();
+ Must(!sslServerBump);
+ HttpRequest *fakeRequest = new HttpRequest;
+ fakeRequest->flags.sslPeek = 1;
+ fakeRequest->SetHost(sslConnectHostOrIp.termedBuf());
+ fakeRequest->port = port;
+ fakeRequest->protocol = AnyP::PROTO_HTTPS;
+ fakeRequest->clientConnectionManager = this;
+ sslServerBump = new Ssl::ServerBump(fakeRequest);
+
// will call httpsPeeked() with certificate and connection, eventually
- AsyncJob::Start(httpsPeeker.raw());
+ FwdState::fwdStart(clientConnection, sslServerBump->entry, sslServerBump->request);
return;
}
void
ConnStateData::httpsPeeked(Comm::ConnectionPointer serverConnection)
{
- Must(httpsPeeker.set());
+ Must(sslServerBump != NULL);
if (Comm::IsConnOpen(serverConnection)) {
SSL *ssl = fd_table[serverConnection->fd].ssl;
// only when bumping CONNECT which uses a host name.
if (intendedDest.IsAnyAddr())
sslCommonName = sslConnectHostOrIp;
- else if (bumpServerCert.get())
- sslCommonName = Ssl::CommonHostName(bumpServerCert.get());
+ else if (sslServerBump->serverCert.get())
+ sslCommonName = Ssl::CommonHostName(sslServerBump->serverCert.get());
}
- if (httpsPeeker.valid())
- httpsPeeker->noteHttpsPeeked(serverConnection);
- httpsPeeker.clear();
getSslContextStart();
}
AsyncJob("ConnStateData"),
#if USE_SSL
switchedToHttps_(false),
+ sslServerBump(NULL),
#endif
stoppedSending_(NULL),
stoppedReceiving_(NULL)
class ConnectionDetail;
#if USE_SSL
namespace Ssl {
- class ServerPeeker;
+ class ServerBump;
}
#endif
/**
void quitAfterError(HttpRequest *request); // meant to be private
#if USE_SSL
- /// called by Ssl::ServerPeeker when it is done bumping the server
+ /// called by FwdState when it is done bumping the server
void httpsPeeked(Comm::ConnectionPointer serverConnection);
/// Start to create dynamic SSL_CTX for host or uses static port SSL context.
void switchToHttps(const char *host, const int port);
bool switchedToHttps() const { return switchedToHttps_; }
- /// Holds the squid error reply in the case of bump server first error
- StoreEntry *bumpServerFirstErrorEntry() const {return bumpErrorEntry;}
- void setBumpServerCert(X509 *serverCert) {bumpServerCert.reset(serverCert);}
- X509 *getBumpServerCert() {return bumpServerCert.get();}
- void setBumpSslErrorList(Ssl::Errors *errNoList) {bumpSslErrorNoList = cbdataReference(errNoList);}
+ Ssl::ServerBump *serverBump() {return sslServerBump;}
/// Fill the certAdaptParams with the required data for certificate adaptation
/// and create the key for storing/retrieve the certificate to/from the cache
void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
String sslCommonName; ///< CN name for SSL certificate generation
String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
- /// a job that connects to the HTTPS server to get its SSL certificate
- CbcPointer<Ssl::ServerPeeker> httpsPeeker;
- StoreEntry *bumpErrorEntry;
- Ssl::X509_Pointer bumpServerCert;
- Ssl::Errors *bumpSslErrorNoList; ///< The list of SSL certificate errors which ignored
+ /// HTTPS server cert. fetching state for bump-ssl-server-first
+ Ssl::ServerBump *sslServerBump;
Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
#endif
#if USE_SSL
#include "ssl/support.h"
#include "ssl/ErrorDetail.h"
-#include "ssl/ServerPeeker.h"
+#include "ssl/ServerBump.h"
#endif
static PSC fwdPeerSelectionCompleteWrapper;
if (request->clientConnectionManager.valid()) {
// Get the server certificate from ErrorDetail object and store it
// to connection manager
- request->clientConnectionManager->setBumpServerCert(X509_dup(errDetails->peerCert()));
+ if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
+ serverBump->serverCert.resetAndLock(errDetails->peerCert());
// if there is a list of ssl errors, pass it to connection manager
- if (Ssl::Errors *errNoList = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_sslerrno)))
- request->clientConnectionManager->setBumpSslErrorList(errNoList);
+ if (Ssl::Errors *errNoList = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_sslerrno)))
+ serverBump->bumpSslErrorNoList = cbdataReference(errNoList);
+ }
}
if (request->flags.sslPeek) {
}
if (request->clientConnectionManager.valid()) {
- request->clientConnectionManager->setBumpServerCert(SSL_get_peer_certificate(ssl));
- if (Ssl::Errors *errNoList = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_sslerrno)))
- request->clientConnectionManager->setBumpSslErrorList(errNoList);
+ if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
+ serverBump->serverCert.reset(SSL_get_peer_certificate(ssl));
+
+ if (Ssl::Errors *errNoList = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_sslerrno)))
+ serverBump->bumpSslErrorNoList = cbdataReference(errNoList);
+ }
}
if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
// store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
X509 *peeked_cert;
- if (request->clientConnectionManager.valid() && (peeked_cert = request->clientConnectionManager->getBumpServerCert())) {
+ if (request->clientConnectionManager.valid() &&
+ request->clientConnectionManager->serverBump() &&
+ (peeked_cert = request->clientConnectionManager->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);
}
ErrorDetail.h \
ErrorDetailManager.cc \
ErrorDetailManager.h \
- ServerPeeker.cc \
- ServerPeeker.h \
+ ServerBump.cc \
+ ServerBump.h \
support.cc \
support.h
--- /dev/null
+/*
+ * $Id$
+ *
+ * DEBUG: section 33 Client-side Routines
+ *
+ */
+
+#include "squid.h"
+
+#include "client_side.h"
+#include "forward.h"
+#include "ssl/ServerBump.h"
+#include "Store.h"
+
+
+CBDATA_NAMESPACED_CLASS_INIT(Ssl, ServerBump);
+
+
+Ssl::ServerBump::ServerBump(HttpRequest *fakeRequest):
+ request(fakeRequest),
+ bumpSslErrorNoList(NULL)
+{
+ debugs(33, 4, HERE << "will peek at " << request->GetHost() << ':' << request->port);
+ const char *uri = urlCanonical(request);
+ entry = storeCreateEntry(uri, uri, request->flags, request->method);
+ // We do not need to be a client because the error contents will be used
+ // later, but an entry without any client will trim all its contents away.
+ sc = storeClientListAdd(entry, this);
+}
+
+Ssl::ServerBump::~ServerBump()
+{
+ debugs(33, 4, HERE << "destroying");
+ if (entry) {
+ debugs(33, 4, HERE << *entry);
+ storeUnregister(sc, entry, this);
+ entry->unlock();
+ }
+ cbdataReferenceDone(bumpSslErrorNoList);
+}
+
--- /dev/null
+#ifndef _SQUID_SSL_PEEKER_H
+#define _SQUID_SSL_PEEKER_H
+
+#include "base/AsyncJob.h"
+#include "base/CbcPointer.h"
+#include "comm/forward.h"
+#include "HttpRequest.h"
+#include "ip/Address.h"
+
+class ConnStateData;
+
+namespace Ssl
+{
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Used to store bump-server-first related informations
+ */
+class ServerBump
+{
+public:
+ explicit ServerBump(HttpRequest *fakeRequest);
+ ~ServerBump();
+ /// faked, minimal request; required by server-side API
+ HttpRequest::Pointer request;
+ StoreEntry *entry; ///< for receiving Squid-generated error messages
+ Ssl::X509_Pointer serverCert; ///< HTTPS server certificate
+ Ssl::Errors *bumpSslErrorNoList; ///< The list of SSL certificate errors which ignored
+
+private:
+ store_client *sc; ///< dummy client to prevent entry trimming
+
+ CBDATA_CLASS2(ServerBump);
+};
+
+} // namespace Ssl
+
+#endif
+++ /dev/null
-/*
- * $Id$
- *
- * DEBUG: section 33 Client-side Routines
- *
- */
-
-#include "squid.h"
-
-#include "client_side.h"
-#include "forward.h"
-#include "ssl/ServerPeeker.h"
-#include "Store.h"
-
-
-CBDATA_NAMESPACED_CLASS_INIT(Ssl, ServerPeeker);
-
-
-Ssl::ServerPeeker::ServerPeeker(ConnStateData *anInitiator,
- const char *host, const int port):
- AsyncJob("Ssl::ServerPeeker"),
- initiator(anInitiator),
- clientConnection(anInitiator->clientConnection),
- request(new HttpRequest),
- entry(NULL),
- sc(NULL)
-{
- debugs(33, 4, HERE << "will peek at " << host << ':' << port);
- request->flags.sslPeek = 1;
- request->SetHost(host);
- request->port = port;
- request->protocol = AnyP::PROTO_HTTPS;
- request->clientConnectionManager = initiator;
- const char *uri = urlCanonical(request);
- entry = storeCreateEntry(uri, uri, request->flags, request->method);
- // We do not need to be a client because the error contents will be used
- // later, but an entry without any client will trim all its contents away.
- sc = storeClientListAdd(entry, this);
-}
-
-Ssl::ServerPeeker::~ServerPeeker()
-{
- if (entry) {
- debugs(33, 4, HERE << "stopped peeking via " << *entry);
- storeUnregister(sc, entry, this);
- entry->unlock();
- }
-}
-
-void
-Ssl::ServerPeeker::start()
-{
- FwdState::fwdStart(clientConnection, entry, request);
-}
-
-void Ssl::ServerPeeker::noteHttpsPeeked(Comm::ConnectionPointer &serverConnection)
-{
- assert(initiator.raw());
- initiator.clear(); // will trigger the end of the job
-}
-
-bool
-Ssl::ServerPeeker::doneAll() const
-{
- return !initiator.valid() && AsyncJob::doneAll();
-}
-
-void
-Ssl::ServerPeeker::swanSong()
-{
-}
+++ /dev/null
-#ifndef _SQUID_SSL_PEEKER_H
-#define _SQUID_SSL_PEEKER_H
-
-#include "base/AsyncJob.h"
-#include "base/CbcPointer.h"
-#include "comm/forward.h"
-#include "HttpRequest.h"
-#include "ip/Address.h"
-
-class ConnStateData;
-
-namespace Ssl
-{
-
-/**
- \ingroup ServerProtocolSSLAPI
- * A job to facilitate connecting to the HTTPS server to learn its certificate.
- *
- * The Peeker job calls FwdState::fwdStart(). There are two possible outcomes:
- *
- * Success: FwdState calls ConnStateData which pins the establihsed connection
- * for future bumped HTTP requests (TODO: and stops this job).
- *
- * Error: FwdState Stores the error (TODO: and this job preserves it for
- * for serving to the client in response to the first bumped request).
- */
-class ServerPeeker: public AsyncJob
-{
-public:
- typedef CbcPointer<ServerPeeker> Pointer;
-
- explicit ServerPeeker(ConnStateData *anInitiator, const char *host, const int port);
-
- /* AsyncJob API */
- virtual ~ServerPeeker();
- virtual void start();
- virtual bool doneAll() const;
- virtual void swanSong();
- StoreEntry *storeEntry() {return entry;}
- void noteHttpsPeeked(Comm::ConnectionPointer &serverConnection);
-
-private:
- /// connection manager waiting for peeked server info
- CbcPointer<ConnStateData> initiator;
-
- /// client-Squid connection which triggered this job
- Comm::ConnectionPointer clientConnection;
-
- /// faked, minimal request; required by server-side API
- HttpRequest::Pointer request;
-
- StoreEntry *entry; ///< for receiving Squid-generated error messages
- store_client *sc; ///< dummy client to prevent entry trimming
-
- CBDATA_CLASS2(ServerPeeker);
-};
-
-} // namespace Ssl
-
-#endif