42 noteFwdPconnUse(false),
43 serverConn(aServerConn),
46 negotiationTimeout(timeout),
48 useCertValidator_(true),
73 debugs(83, 5,
"this=" << (
void*)
this);
78 if (
fd_table[serverConn->fd].closing()) {
87 mustStop(
"Security::PeerConnector TLS socket initialize failed");
95 checklist.
syncAle(request.getRaw(),
nullptr);
100 if (
const auto session =
fd_table[serverConnection()->fd].ssl.get())
111 debugs(83, 5,
"FD " << params.
fd <<
", Security::PeerConnector=" << params.
data);
113 closeHandler =
nullptr;
120 countFailingConnection();
121 serverConn->noteClosure();
122 serverConn =
nullptr;
131 debugs(83, 5, serverConnection() <<
" timedout. this=" << (
void*)
this);
143 const auto ctx = peerContext();
144 debugs(83, 5, serverConnection() <<
", ctx=" << ctx);
147 const auto xerrno = errno;
152 anErr->xerrno = xerrno;
153 noteNegotiationDone(anErr);
159 serverSession =
fd_table[serverConnection()->fd].ssl;
160 debugs(83, 5, serverConnection() <<
", session=" << (
void*)serverSession.get());
173 fillChecklist(*check);
181 const auto cycle = certDownloadNestingLevel() >= MaxNestedDownloads;
183 debugs(83, 3,
"will not fetch any missing certificates; suspecting cycle: " << certDownloadNestingLevel() <<
'/' << MaxNestedDownloads);
186 sessData->callerHandlesMissingCertificates = !cycle;
197 const int fd = serverConnection()->fd;
201 serverConnection()->tlsNegotiations()->retrieveNegotiatedInfo(session);
205 BIO *b = SSL_get_rbio(session.get());
208 serverConnection()->tlsNegotiations()->retrieveParsedInfo(details);
217 const int fd = serverConnection()->fd;
227 keyLogger.checkpoint(sconn, *
this);
244 hidMissingIssuer =
false;
247 !(result.errorDetail && result.errorDetail->errorNo() == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY))
248 return handleMissingCertificates(result);
250 debugs(83,
DBG_IMPORTANT,
"ERROR: Squid BUG: Honoring unexpected SSL_connect() failure: X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY");
255 handleNegotiationResult(result);
263 recordNegotiationDetails();
264 if (sslFinalized() && callback)
281 debugs(83, 2,
"ERROR: Cannot establish a TLS connection" <<
284 recordNegotiationDetails();
294 const int fd = serverConnection()->fd;
302 validationRequest.
ssl = session;
304 validationRequest.
domainName = dName->c_str();
307 validationRequest.
errors = errs;
309 debugs(83, 5,
"Sending SSL certificate for validation to ssl_crtvd.");
313 }
catch (
const std::exception &e) {
315 "request for " << validationRequest.
domainName <<
316 " certificate: " << e.what() <<
"; will now block to " <<
317 "validate that certificate.");
321 noteNegotiationDone(anErr);
328 noteNegotiationDone(
nullptr);
336 Must(validationResponse !=
nullptr);
340 bool validatorFailed =
false;
345 debugs(83, 5,
"cert validation result: " << validationResponse->resultCode <<
RawPointer(
" host: ",
server));
356 validatorFailed =
true;
358 if (!errDetails && !validatorFailed) {
359 noteNegotiationDone(
nullptr);
366 if (validatorFailed) {
374 noteNegotiationDone(anErr);
391 std::optional<ACLFilledChecklist> check;
393 check.emplace(acl, request.getRaw());
394 fillChecklist(*check);
398 typedef Ssl::CertValidationResponse::RecvdErrors::const_iterator SVCRECI;
399 for (SVCRECI i = resp.
errors.begin(); i != resp.
errors.end(); ++i) {
400 debugs(83, 7,
"Error item: " << i->error_no <<
" " << i->error_reason);
402 assert(i->error_no != SSL_ERROR_NONE);
405 bool allowed =
false;
407 const auto sslErrors = std::make_unique<Security::CertErrors>(
Security::CertError(i->error_no, i->cert, i->error_depth));
408 check->sslErrors = sslErrors.get();
409 if (check->fastCheck().allowed())
411 check->sslErrors.clear();
417 debugs(83, 3,
"bypassing SSL error " << i->error_no <<
" in " <<
"buffer");
419 debugs(83, 5,
"confirming SSL error " << i->error_no);
426 const auto &brokenCert = i->cert ? i->cert : peerCert;
428 const char *aReason = i->error_reason.empty() ? nullptr : i->error_reason.c_str();
429 errDetails =
new ErrorDetail(i->error_no, peerCert, brokenCert, aReason);
449 (*pc)->negotiateSsl();
464 debugs(83, 5, serverConnection());
467 const int fd = serverConnection()->fd;
482 debugs(83, 5, serverConnection());
485 const int fd = serverConnection()->fd;
496 anErr->detailError(detail);
498 noteNegotiationDone(anErr);
506 return callback.answer();
513 answer().error =
error;
515 if (
const auto failingConnection = serverConn) {
516 countFailingConnection();
518 failingConnection->close();
528 answer().conn = serverConn;
539 if (noteFwdPconnUse && serverConn->isOpen())
551 closeHandler =
nullptr;
557 serverConn =
nullptr;
563 debugs(83, 5,
"TLS setup ended for " << answer().conn);
592 if (stopReason !=
nullptr) {
593 buf.
append(
"Stopped, reason:", 16);
597 buf.
appendf(
" FD %d", serverConn->fd);
598 buf.
appendf(
" %s%u]",
id.prefix(),
id.value);
613 if (
const auto previousDownloader = request->downloader.get())
614 return previousDownloader->nestedLevel();
623 const auto dl =
new Downloader(url, certCallback,
624 MasterXaction::MakePortless<XactionInitiator::initCertFetcher>(),
625 certDownloadNestingLevel() + 1);
626 certDownloadWait.start(dl, certCallback);
632 certDownloadWait.finish();
638 const auto &sconn = *
fd_table[serverConnection()->fd].ssl;
648 auto raw =
reinterpret_cast<const unsigned char*
>(downloaderAnswer.
resource.
rawContent());
649 if (
auto cert = d2i_X509(
nullptr, &raw, downloaderAnswer.
resource.
length())) {
650 debugs(81, 5,
"Retrieved certificate: " << *cert);
652 if (!downloadedCerts)
653 downloadedCerts.reset(sk_X509_new_null());
654 sk_X509_push(downloadedCerts.get(), cert);
656 const auto ctx = peerContext()->raw;
657 const auto certsList = SSL_get_peer_cert_chain(&sconn);
660 debugs(81, 5,
"certificate " << *cert <<
661 " points to its missing issuer certificate at " << issuerUri);
662 urlsOfMissingCerts.push(
SBuf(issuerUri));
664 debugs(81, 3,
"found a certificate with no IAI, " <<
665 "signed by a missing issuer certificate: " << *cert);
676 if (urlsOfMissingCerts.size() && certsDownloads <= MaxCertsDownloads) {
677 startCertDownloading(urlsOfMissingCerts.front());
678 urlsOfMissingCerts.pop();
689 auto &sconn = *
fd_table[serverConnection()->fd].ssl;
697 Must(callerHandlesMissingCertificates);
698 callerHandlesMissingCertificates =
false;
700 suspendNegotiation(ioResult);
702 if (!computeMissingCertificateUrls(sconn))
703 return resumeNegotiation();
705 assert(!urlsOfMissingCerts.empty());
706 startCertDownloading(urlsOfMissingCerts.front());
707 urlsOfMissingCerts.pop();
714 const auto certs = SSL_get_peer_cert_chain(&sconn);
716 debugs(83, 3,
"nothing to bootstrap the fetch with");
719 debugs(83, 5,
"server certificates: " << sk_X509_num(certs));
721 const auto optionalContext = peerContext();
722 if (!optionalContext) {
723 debugs(83, 3,
"cannot compute due to disabled TLS support");
726 const auto ctx = optionalContext->raw;
730 debugs(83, 5,
"URLs: " << urlsOfMissingCerts.size());
731 assert(!urlsOfMissingCerts.empty());
738 debugs(83, 5,
"after " << ioResult);
739 Must(!isSuspended());
750 auto lastError = suspendedError_;
751 suspendedError_ =
nullptr;
753 auto &sconn = *
fd_table[serverConnection()->fd].ssl;
762 handleNegotiationResult(*lastError);
#define Assure(condition)
#define ScheduleCallHere(call)
#define asyncCallback(dbgSection, dbgLevel, method, object)
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
#define CallJobHere(debugSection, debugLevel, job, Class, method)
void NoteOutgoingConnectionFailure(CachePeer *const peer)
ErrorDetail::Pointer MakeNamedErrorDetail(const char *name)
PconnPool * fwdPconnPool
a collection of previously used persistent Squid-to-peer HTTP(S) connections
RawPointerT< Pointer > RawPointer(const char *label, const Pointer &ptr)
convenience wrapper for creating RawPointerT<> objects
void error(char *format,...)
static char server[MAXLINE]
static MakingPointer Make(const acl_access *a, HttpRequest *r)
Security::CertPointer serverCert
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override
assigns uninitialized adapted_request and url ALE components
a smart AsyncCall pointer for delivery of future results
virtual bool doneAll() const
whether positive goal has been reached
virtual void start()
called by AsyncStart; do not call directly
bool push_back_unique(C const &element)
int fd
FD which the call was about. Set by the async call creator.
static bool Enabled(const int section, const int level)
whether debugging the given section and the given level produces output
static std::ostream & Extra(std::ostream &)
static ErrorState * NewForwarding(err_type, HttpRequestPointer &, const AccessLogEntryPointer &)
Creates a general request forwarding error with the right http_status.
void detailError(const ErrorDetail::Pointer &dCode)
set error type-specific detail code
void append(const char *c, int sz) override
char * content()
start of the added data
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
const char * rawContent() const
size_type length() const
Returns the number of bytes stored in SBuf.
a summary a TLS I/O operation outcome
ErrorDetailPointer errorDetail
ioError case details (or nil)
Category category
primary outcome classification
void resetWithoutLocking(T *t)
Reset raw pointer - unlock any previous one and save new one without locking.
void countFailingConnection()
updates connection usage history before the connection is closed
void negotiateSsl()
Comm::SetSelect() callback. Direct calls tickle/resume negotiations.
void commCloseHandler(const CommCloseCbParams ¶ms)
The comm_close callback handler.
void sslCrtvdHandleReply(Ssl::CertValidationResponsePointer &)
Process response from cert validator helper.
AsyncCall::Pointer closeHandler
we call this when the connection closed
void startCertDownloading(SBuf &url)
Start downloading procedure for the given URL.
virtual bool initialize(Security::SessionPointer &)
PeerConnector(const Comm::ConnectionPointer &aServerConn, const AsyncCallback< EncryptorAnswer > &, const AccessLogEntryPointer &alp, const time_t timeout=0)
void bail(ErrorState *error)
sends the given error to the initiator
virtual void noteNegotiationError(const Security::ErrorDetailPointer &)
Called when the SSL_connect function aborts with an SSL negotiation error.
EncryptorAnswer & answer()
convenience method to get to the answer fields
~PeerConnector() override
virtual void noteWantWrite()
bool computeMissingCertificateUrls(const Connection &)
finds URLs of (some) missing intermediate certificates or returns false
void handleMissingCertificates(const Security::IoResult &lastError)
Either initiates fetching of missing certificates or bails with an error.
void resumeNegotiation()
Resumes TLS negotiation paused by suspendNegotiation()
void start() override
Preps connection and SSL state. Calls negotiate().
void handleNegotiationResult(const Security::IoResult &)
Called after each negotiation step to handle the result.
void commTimeoutHandler(const CommTimeoutCbParams &)
The connection read timeout callback handler.
void fillChecklist(ACLFilledChecklist &) const override
configure the given checklist (to reflect the current transaction state)
bool doneAll() const override
whether positive goal has been reached
static void NegotiateSsl(int fd, void *data)
A wrapper for Comm::SetSelect() notifications.
void disconnect()
a bail(), sendSuccess() helper: stops monitoring the connection
void sendSuccess()
sends the encrypted connection to the initiator
void certDownloadingDone(DownloaderAnswer &)
Called by Downloader after a certificate object downloaded.
unsigned int certDownloadNestingLevel() const
the number of concurrent PeerConnector jobs waiting for us
void callBack()
a bail(), sendSuccess() helper: sends results to the initiator
Comm::ConnectionPointer serverConn
TCP connection to the peer.
void suspendNegotiation(const Security::IoResult &lastError)
const char * status() const override
internal cleanup; do not call directly
Security::CertErrors * sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &, ErrorDetailPointer &)
Check SSL errors returned from cert validator against sslproxy_cert_error access list.
void recordNegotiationDetails()
static void Submit(const Ssl::CertValidationRequest &, const Callback &)
Submit crtd request message to external crtd server.
Security::SessionPointer ssl
Security::CertErrors * errors
The list of errors detected.
std::string domainName
The server name.
RecvdErrors errors
The list of parsed errors.
const Security::TlsDetails::Pointer & receivedHelloDetails() const
static VerifyCallbackParameters & At(Security::Connection &)
static VerifyCallbackParameters * New(Security::Connection &)
bool callerHandlesMissingCertificates
void commUnsetConnTimeout(const Comm::ConnectionPointer &conn)
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
#define debugs(SECTION, LEVEL, CONTENT)
#define COMM_SELECT_WRITE
@ ERR_SECURE_CONNECT_FAIL
int ssl_ex_index_ssl_errors
int ssl_ex_index_cert_error_check
bool IsConnOpen(const Comm::ConnectionPointer &conn)
time_t MortalReadTimeout(const time_t startTime, const time_t lifetimeLimit)
maximum read delay for readers with limited lifetime
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
bool CreateClientSession(FuturePeerContext &, const Comm::ConnectionPointer &, const char *squidCtx)
std::shared_ptr< SSL > SessionPointer
IoResult Connect(Comm::Connection &transport)
establish a TLS connection over the specified from-Squid transport connection
CbDataList< Security::CertError > CertErrors
Holds a list of X.509 certificate errors.
bool VerifyConnCertificates(Security::Connection &, const Ssl::X509_STACK_Pointer &extraCerts)
Security::CertPointer findIssuerCertificate(X509 *cert, const STACK_OF(X509) *serverCertificates, const Security::ContextPointer &context)
bool missingChainCertificatesUrls(std::queue< SBuf > &URIs, const STACK_OF(X509) &serverCertificates, const Security::ContextPointer &context)
const char * findIssuerUri(X509 *cert)
finds certificate issuer URI in the Authority Info Access extension
void * BIO_get_data(BIO *table)
@ SQUID_TLS_ERR_CONNECT
failure to establish a connection with a TLS server