s->version, s->cipher, s->options, s->sslflags, s->clientca,
s->cafile, s->capath, s->crlfile, s->dhfile,
s->sslContextSessionId));
+
+ if (s->cert && s->key && s->sslBump)
+ Ssl::readCertChainAndPrivateKeyFromFiles(s->signingCert, s->signPkey, s->certsToChain, s->cert, s->key);
}
}
if (bodyPipe != NULL)
stopProducingFor(bodyPipe, false);
+
+#if USE_SSL
+ if (bumpErrorEntry)
+ bumpErrorEntry->unlock();
+#endif
}
/**
conn->flags.readMore = false;
}
+#if USE_SSL
+ if (conn->switchedToHttps() && conn->bumpServerFirstErrorEntry() &&
+ !Comm::IsConnOpen(conn->pinning.serverConnection)) {
+ //Failed? Here we should get the error from conn and send it to client
+ // The error stored in ConnStateData::bumpFirstEntry, replace the
+ // ClientHttpRequest store entry with this.
+ clientStreamNode *node = context->getClientReplyContext();
+ clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
+ assert (repContext);
+ debugs(33, 5, "Connection first has failed for " << http->uri << ". Respond with an error");
+ StoreEntry *e = conn->bumpServerFirstErrorEntry();
+ Must(e && !e->isEmpty());
+ repContext->setReplyToStoreEntry(e);
+ context->pullData();
+ conn->flags.readMore = false;
+ goto finish;
+ }
+#endif
+
/* Do we expect a request-body? */
expectBody = chunked || request->content_length > 0;
if (!context->mayUseConnection() && expectBody) {
debugs(33, 5, HERE << "SSL certificate for " << host << " haven't found in cache");
}
- Ssl::X509_Pointer serverCert;
- if (Comm::IsConnOpen(pinning.serverConnection)) {
- SSL *ssl = fd_table[pinning.serverConnection->fd].ssl;
- serverCert.reset(SSL_get_peer_certificate(ssl));
- }
-
#if USE_SSL_CRTD
debugs(33, 5, HERE << "Generating SSL certificate for " << host << " using ssl_crtd.");
Ssl::CrtdMessage request_message;
map.insert(std::make_pair(Ssl::CrtdMessage::param_host, host));
std::string bufferToWrite;
Ssl::writeCertAndPrivateKeyToMemory(port->signingCert, port->signPkey, bufferToWrite);
- if (serverCert.get()) {
- Ssl::appendCertToMemory(serverCert, bufferToWrite);
+ if (bumpServerCert.get()) {
+ Ssl::appendCertToMemory(bumpServerCert, bufferToWrite);
debugs(33, 5, HERE << "Append Mimic Certificate to body request: " << bufferToWrite);
}
request_message.composeBody(map, bufferToWrite);
return;
#else
debugs(33, 5, HERE << "Generating SSL certificate for " << host);
- dynCtx = Ssl::generateSslContext(host, serverCert, port->signingCert, port->signPkey);
+ dynCtx = Ssl::generateSslContext(host, bumpServerCert, port->signingCert, port->signPkey);
getSslContextDone(dynCtx, true);
return;
#endif //USE_SSL_CRTD
const bool alwaysBumpServerFirst = true;
if (alwaysBumpServerFirst) {
Must(!httpsPeeker.set());
- httpsPeeker = AsyncJob::Start(new Ssl::ServerPeeker(
- this, sslHostName.termedBuf(), port));
+ httpsPeeker = new Ssl::ServerPeeker(this, sslHostName.termedBuf(), port);
+ bumpErrorEntry = httpsPeeker->storeEntry();
+ Must(bumpErrorEntry);
+ bumpErrorEntry->lock();
// will call httpsPeeked() with certificate and connection, eventually
+ AsyncJob::Start(httpsPeeker.raw());
return;
}
{
Must(httpsPeeker.set());
- /* XXX: handle httpsPeeker errors instead of asserting there are none */
- assert(Comm::IsConnOpen(serverConnection));
- SSL *ssl = fd_table[serverConnection->fd].ssl;
- assert(ssl);
- Ssl::X509_Pointer serverCert(SSL_get_peer_certificate(ssl));
- assert(serverCert.get() != NULL);
-
- char name[256] = ""; // stores common name (CN)
- // TODO: What if CN is a UTF8String? See X509_NAME_get_index_by_NID(3ssl).
- const int nameLen = X509_NAME_get_text_by_NID(
- X509_get_subject_name(serverCert.get()),
- NID_commonName, name, sizeof(name));
- assert(0 < nameLen && nameLen < static_cast<int>(sizeof(name)));
- debugs(33, 5, HERE << "found HTTPS server " << name << " at bumped " <<
- *serverConnection);
- sslHostName = name;
-
- pinConnection(serverConnection, NULL, NULL, false);
-
- debugs(33, 5, HERE << "bumped HTTPS server: " << sslHostName);
+ if (Comm::IsConnOpen(serverConnection)) {
+ SSL *ssl = fd_table[serverConnection->fd].ssl;
+ assert(ssl);
+ Ssl::X509_Pointer serverCert(SSL_get_peer_certificate(ssl));
+ assert(serverCert.get() != NULL);
+
+ char name[256] = ""; // stores common name (CN)
+ // TODO: What if CN is a UTF8String? See X509_NAME_get_index_by_NID(3ssl).
+ const int nameLen = X509_NAME_get_text_by_NID(
+ X509_get_subject_name(serverCert.get()),
+ NID_commonName, name, sizeof(name));
+ assert(0 < nameLen && nameLen < static_cast<int>(sizeof(name)));
+ debugs(33, 5, HERE << "found HTTPS server " << name << " at bumped " <<
+ *serverConnection);
+ sslHostName = name;
+
+ pinConnection(serverConnection, NULL, NULL, false);
+
+ debugs(33, 5, HERE << "bumped HTTPS server: " << sslHostName);
+ } else
+ debugs(33, 5, HERE << "Error while bumped HTTPS server: " << sslHostName);
+
+ if (httpsPeeker.valid())
+ httpsPeeker->noteHttpsPeeked(serverConnection);
httpsPeeker.clear();
getSslContextStart();
}
ConnStateData::ConnStateData() :
AsyncJob("ConnStateData"),
- closing_(false),
- switchedToHttps_(false)
+ closing_(false)
+#if USE_SSL
+ ,switchedToHttps_(false)
+#endif
{
pinning.pinned = false;
pinning.auth = false;
#include "HttpParser.h"
#include "RefCount.h"
#include "StoreIOBuffer.h"
+#if USE_SSL
+#include "ssl/support.h"
+#endif
class ConnStateData;
class ClientHttpRequest;
class ConnectionDetail;
-
+#if USE_SSL
+namespace Ssl {
+ class ServerPeeker;
+}
+#endif
/**
* Manages a connection to a client.
*
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);}
#else
bool switchedToHttps() const { return false; }
#endif
String sslHostName; ///< Host name for SSL certificate generation
/// a job that connects to the HTTPS server to get its SSL certificate
- AsyncJob::Pointer httpsPeeker;
+ CbcPointer<Ssl::ServerPeeker> httpsPeeker;
+ StoreEntry *bumpErrorEntry;
+ Ssl::X509_Pointer bumpServerCert;
#endif
AsyncCall::Pointer reader; ///< set when we are reading
/* Now the caller reads to get this */
}
+void clientReplyContext::setReplyToStoreEntry(StoreEntry *entry)
+{
+ sc = storeClientListAdd(entry, this);
+#if USE_DELAY_POOLS
+ sc->setDelayId(DelayId::DelayClient(http));
+#endif
+ reqofs = 0;
+ reqsize = 0;
+ flags.storelogiccomplete = 1;
+ http->storeEntry(entry);
+}
+
void
clientReplyContext::removeStoreReference(store_client ** scp,
StoreEntry ** ep)
void identifyFoundObject(StoreEntry *entry);
int storeOKTransferDone() const;
int storeNotOKTransferDone() const;
+ /// Replaces the store entry with the given and awaiting the client side to read it
+ void setReplyToStoreEntry(StoreEntry *entry);
void setReplyToError(err_type, http_status, const HttpRequestMethod&, char const *, Ip::Address &, HttpRequest *, const char *,
#if USE_AUTH
AuthUserRequest::Pointer);
#if USE_SSL
#include "ssl/support.h"
#include "ssl/ErrorDetail.h"
+#include "ssl/ServerPeeker.h"
#endif
static PSC fwdPeerSelectionCompleteWrapper;
p->peerType = PINNED;
entry->ping_status = PING_DONE; /* Skip ICP */
} else {
- debugs(17, 3, HERE << "opening a new conn: " << *p);
p = new Comm::Connection();
p->peerType = ORIGINAL_DST;
p->remote = clientConn->local;
getOutgoingAddress(request, p);
+ debugs(17, 3, HERE << "opening a new conn: " << *p);
}
serverDestinations.push_back(p);
anErr->xerrno = errno;
fail(anErr);
} // else use actual error from last connection attempt
+#if USE_SSL
+ if (request->protocol == AnyP::PROTO_SSL_PEEK && request->clientConnectionManager.valid()) {
+ errorAppendEntry(entry, err); // will free err
+ err = NULL;
+ CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData,
+ ConnStateData::httpsPeeked, Comm::ConnectionPointer(NULL));
+ }
+#endif
self = NULL; // refcounted
}
}
// Copy errFromFailure to a new Ssl::ErrorDetail object
anErr->detail = new Ssl::ErrorDetail(*errFromFailure);
} else {
- // clientCert can be be NULL
- X509 *client_cert = SSL_get_peer_certificate(ssl);
- anErr->detail = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, client_cert);
- if (client_cert)
- X509_free(client_cert);
+ // server_cert can be be NULL
+ X509 *server_cert = SSL_get_peer_certificate(ssl);
+ anErr->detail = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, server_cert);
+ X509_free(server_cert);
}
if (ssl_lib_error != SSL_ERROR_NONE)
anErr->detail->setLibError(ssl_lib_error);
+ if (request->clientConnectionManager.valid()) {
+ // Get the server certificate from ErrorDetail object and store it
+ // to connection manager
+ X509 *x509 = anErr->detail->peerCert();
+ request->clientConnectionManager->setBumpServerCert(X509_dup(x509));
+ }
+
fail(anErr);
if (serverConnection()->getPeer()) {
return;
}
}
+
+ if (request->clientConnectionManager.valid())
+ request->clientConnectionManager->setBumpServerCert(SSL_get_peer_certificate(ssl));
if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
if (serverConnection()->getPeer()->sslSession)
#if USE_SSL
if (request->protocol == AnyP::PROTO_SSL_PEEK) {
CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData,
- ConnStateData::httpsPeeked, serverConnection());
+ ConnStateData::httpsPeeked, serverConnection());
unregister(serverConn); // async call owns it now
complete(); // destroys us
return;
- }
+ }
#endif
if (serverConnection()->getPeer() != NULL) {
ssl_error_t errorNo() const {return error_no;}
///Sets the low-level error returned by OpenSSL ERR_get_error()
void setLibError(unsigned long lib_err_no) {lib_error_no = lib_err_no;}
-
+ ///The peer certificate
+ X509 *peerCert() { return peer_cert.get(); }
private:
typedef const char * (ErrorDetail::*fmt_action_t)() const;
/**
AsyncJob("Ssl::ServerPeeker"),
initiator(anInitiator),
clientConnection(anInitiator->clientConnection),
- request(new HttpRequest),
- entry(NULL)
+ request(new HttpRequest)
{
debugs(33, 4, HERE << "will peek at " << host << ':' << port);
request->port = port;
request->protocol = AnyP::PROTO_SSL_PEEK;
request->clientConnectionManager = initiator;
+ const char *uri = urlCanonical(request);
+ entry = storeCreateEntry(uri, uri, request->flags, request->method);
+}
+
+Ssl::ServerPeeker::~ServerPeeker()
+{
+ if (entry)
+ entry->unlock();
}
void
Ssl::ServerPeeker::start()
{
- const char *uri = urlCanonical(request);
- entry = storeCreateEntry(uri, uri, request->flags, request->method);
-
FwdState::fwdStart(clientConnection, entry, request);
+}
- // XXX: wait for FwdState to tell us the connection is ready
-
- // TODO: send our answer to the initiator
- // CallJobHere(33, 4, initiator, ConnStateData, ConnStateData::httpsPeeked);
+void Ssl::ServerPeeker::noteHttpsPeeked(Comm::ConnectionPointer &serverConnection)
+{
+ assert(initiator.raw());
initiator.clear(); // will trigger the end of the job
}
explicit ServerPeeker(ConnStateData *anInitiator, const char *host, const int port);
/* AsyncJob API */
- //virtual ~ServerPeeker();
+ 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