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);
420 const auto &brokenCert = i->cert;
422 const char *aReason = i->error_reason.empty() ? nullptr : i->error_reason.c_str();
423 errDetails =
new ErrorDetail(i->error_no, peerCert, brokenCert, aReason);
443 (*pc)->negotiateSsl();
458 debugs(83, 5, serverConnection());
461 const int fd = serverConnection()->fd;
476 debugs(83, 5, serverConnection());
479 const int fd = serverConnection()->fd;
490 anErr->detailError(detail);
492 noteNegotiationDone(anErr);
500 return callback.answer();
507 answer().error =
error;
509 if (
const auto failingConnection = serverConn) {
510 countFailingConnection();
512 failingConnection->close();
522 answer().conn = serverConn;
533 if (noteFwdPconnUse && serverConn->isOpen())
545 closeHandler =
nullptr;
551 serverConn =
nullptr;
557 debugs(83, 5,
"TLS setup ended for " << answer().conn);
586 if (stopReason !=
nullptr) {
587 buf.
append(
"Stopped, reason:", 16);
591 buf.
appendf(
" FD %d", serverConn->fd);
592 buf.
appendf(
" %s%u]",
id.prefix(),
id.value);
607 if (
const auto previousDownloader = request->downloader.get())
608 return previousDownloader->nestedLevel();
617 const auto dl =
new Downloader(url, certCallback,
618 MasterXaction::MakePortless<XactionInitiator::initCertFetcher>(),
619 certDownloadNestingLevel() + 1);
620 certDownloadWait.start(dl, certCallback);
626 certDownloadWait.finish();
632 const auto &sconn = *
fd_table[serverConnection()->fd].ssl;
642 auto raw =
reinterpret_cast<const unsigned char*
>(downloaderAnswer.
resource.
rawContent());
643 if (
auto cert = d2i_X509(
nullptr, &raw, downloaderAnswer.
resource.
length())) {
644 debugs(81, 5,
"Retrieved certificate: " << *cert);
646 if (!downloadedCerts)
647 downloadedCerts.reset(sk_X509_new_null());
648 sk_X509_push(downloadedCerts.get(), cert);
650 const auto ctx = peerContext()->raw;
651 const auto certsList = SSL_get_peer_cert_chain(&sconn);
654 debugs(81, 5,
"certificate " << *cert <<
655 " points to its missing issuer certificate at " << issuerUri);
656 urlsOfMissingCerts.push(
SBuf(issuerUri));
658 debugs(81, 3,
"found a certificate with no IAI, " <<
659 "signed by a missing issuer certificate: " << *cert);
670 if (urlsOfMissingCerts.size() && certsDownloads <= MaxCertsDownloads) {
671 startCertDownloading(urlsOfMissingCerts.front());
672 urlsOfMissingCerts.pop();
683 auto &sconn = *
fd_table[serverConnection()->fd].ssl;
691 Must(callerHandlesMissingCertificates);
692 callerHandlesMissingCertificates =
false;
694 suspendNegotiation(ioResult);
696 if (!computeMissingCertificateUrls(sconn))
697 return resumeNegotiation();
699 assert(!urlsOfMissingCerts.empty());
700 startCertDownloading(urlsOfMissingCerts.front());
701 urlsOfMissingCerts.pop();
708 const auto certs = SSL_get_peer_cert_chain(&sconn);
710 debugs(83, 3,
"nothing to bootstrap the fetch with");
713 debugs(83, 5,
"server certificates: " << sk_X509_num(certs));
715 const auto optionalContext = peerContext();
716 if (!optionalContext) {
717 debugs(83, 3,
"cannot compute due to disabled TLS support");
720 const auto ctx = optionalContext->raw;
724 debugs(83, 5,
"URLs: " << urlsOfMissingCerts.size());
725 assert(!urlsOfMissingCerts.empty());
732 debugs(83, 5,
"after " << ioResult);
733 Must(!isSuspended());
744 auto lastError = suspendedError_;
745 suspendedError_ =
nullptr;
747 auto &sconn = *
fd_table[serverConnection()->fd].ssl;
756 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