2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 #ifndef SQUID_SRC_SECURITY_PEERCONNECTOR_H
10 #define SQUID_SRC_SECURITY_PEERCONNECTOR_H
13 #include "acl/ChecklistFiller.h"
14 #include "base/AsyncCallbacks.h"
15 #include "base/AsyncJob.h"
16 #include "base/JobWait.h"
17 #include "CommCalls.h"
18 #include "http/forward.h"
19 #include "security/EncryptorAnswer.h"
20 #include "security/forward.h"
21 #include "security/KeyLogger.h"
23 #include "ssl/support.h"
30 class DownloaderAnswer
;
32 typedef RefCount
<AccessLogEntry
> AccessLogEntryPointer
;
38 typedef RefCount
<IoResult
> IoResultPointer
;
41 * Initiates encryption of a given open TCP connection to a peer or server.
42 * Despite its name does not perform any connect(2) operations. Owns the
43 * connection during TLS negotiations. The caller receives EncryptorAnswer.
45 * Contains common code and interfaces of various specialized PeerConnector's,
46 * including peer certificate validation code.
48 class PeerConnector
: virtual public AsyncJob
, public Acl::ChecklistFiller
50 CBDATA_INTERMEDIATE();
53 typedef CbcPointer
<PeerConnector
> Pointer
;
55 PeerConnector(const Comm::ConnectionPointer
&aServerConn
,
56 const AsyncCallback
<EncryptorAnswer
> &,
57 const AccessLogEntryPointer
&alp
,
58 const time_t timeout
= 0);
59 ~PeerConnector() override
;
61 /// hack: whether the connection requires fwdPconnPool->noteUses()
66 void start() override
;
67 bool doneAll() const override
;
68 void swanSong() override
;
69 const char *status() const override
;
71 /* Acl::ChecklistFiller API */
72 void fillChecklist(ACLFilledChecklist
&) const override
;
74 /// The connection read timeout callback handler.
75 void commTimeoutHandler(const CommTimeoutCbParams
&);
77 /// The comm_close callback handler.
78 void commCloseHandler(const CommCloseCbParams
¶ms
);
80 /// \returns true on successful TLS session initialization
81 virtual bool initialize(Security::SessionPointer
&);
83 /// Performs a single secure connection negotiation step.
84 /// It is called multiple times until the negotiation finishes or aborts.
87 /// Called after negotiation has finished. Cleans up TLS/SSL state.
88 /// Returns false if we are now waiting for the certs validation job.
89 /// Otherwise, returns true, regardless of negotiation success/failure.
92 /// Called after each negotiation step to handle the result
93 void handleNegotiationResult(const Security::IoResult
&);
95 /// Called when the openSSL SSL_connect fnction request more data from
96 /// the remote SSL server. Sets the read timeout and sets the
97 /// Squid COMM_SELECT_READ handler.
100 /// Whether TLS negotiation has been paused and not yet resumed
101 bool isSuspended() const { return static_cast<bool>(suspendedError_
); }
104 /// Suspends TLS negotiation to download the missing certificates
105 /// \param lastError an error to handle when resuming negotiations
106 void suspendNegotiation(const Security::IoResult
&lastError
);
108 /// Resumes TLS negotiation paused by suspendNegotiation()
109 void resumeNegotiation();
111 /// Either initiates fetching of missing certificates or bails with an error
112 void handleMissingCertificates(const Security::IoResult
&lastError
);
114 /// Start downloading procedure for the given URL.
115 void startCertDownloading(SBuf
&url
);
117 /// Called by Downloader after a certificate object downloaded.
118 void certDownloadingDone(DownloaderAnswer
&);
121 /// Called when the openSSL SSL_connect function needs to write data to
122 /// the remote SSL server. Sets the Squid COMM_SELECT_WRITE handler.
123 virtual void noteWantWrite();
125 /// Called when the SSL_connect function aborts with an SSL negotiation error
126 virtual void noteNegotiationError(const Security::ErrorDetailPointer
&);
128 /// Called when the SSL negotiation to the server completed and the certificates
129 /// validated using the cert validator.
130 /// \param error if not NULL the SSL negotiation was aborted with an error
131 virtual void noteNegotiationDone(ErrorState
*) {}
133 /// peer's security context
134 /// \returns nil if Squid is built without TLS support (XXX: Prevent PeerConnector creation in those cases instead)
135 virtual FuturePeerContext
*peerContext() const = 0;
137 /// mimics FwdState to minimize changes to FwdState::initiate/negotiateSsl
138 Comm::ConnectionPointer
const &serverConnection() const { return serverConn
; }
140 /// sends the given error to the initiator
141 void bail(ErrorState
*error
);
143 /// sends the encrypted connection to the initiator
146 /// a bail(), sendSuccess() helper: sends results to the initiator
149 /// a bail(), sendSuccess() helper: stops monitoring the connection
152 /// updates connection usage history before the connection is closed
153 void countFailingConnection();
155 /// If called the certificates validator will not used
156 void bypassCertValidator() {useCertValidator_
= false;}
158 /// Called after negotiation finishes to record connection details for
160 void recordNegotiationDetails();
162 /// convenience method to get to the answer fields
163 EncryptorAnswer
&answer();
165 HttpRequestPointer request
; ///< peer connection trigger or cause
166 Comm::ConnectionPointer serverConn
; ///< TCP connection to the peer
167 AccessLogEntryPointer al
; ///< info for the future access.log entry
169 /// answer destination
170 AsyncCallback
<EncryptorAnswer
> callback
;
173 PeerConnector(const PeerConnector
&); // not implemented
174 PeerConnector
&operator =(const PeerConnector
&); // not implemented
177 unsigned int certDownloadNestingLevel() const;
179 /// Process response from cert validator helper
180 void sslCrtvdHandleReply(Ssl::CertValidationResponsePointer
&);
182 /// Check SSL errors returned from cert validator against sslproxy_cert_error access list
183 Security::CertErrors
*sslCrtvdCheckForErrors(Ssl::CertValidationResponse
const &, ErrorDetailPointer
&);
185 bool computeMissingCertificateUrls(const Connection
&);
188 static void NegotiateSsl(int fd
, void *data
);
191 /// The maximum number of missing certificates a single PeerConnector may download
192 static const unsigned int MaxCertsDownloads
= 10;
194 /// The maximum number of inter-dependent Downloader jobs a worker may initiate
195 static const unsigned int MaxNestedDownloads
= 3;
197 /// managers logging of the being-established TLS connection secrets
198 Security::KeyLogger keyLogger
;
200 AsyncCall::Pointer closeHandler
; ///< we call this when the connection closed
201 time_t negotiationTimeout
; ///< the SSL connection timeout to use
202 time_t startTime
; ///< when the peer connector negotiation started
203 bool useCertValidator_
; ///< whether the certificate validator should bypassed
204 /// The list of URLs where missing certificates should be downloaded.
205 std::queue
<SBuf
> urlsOfMissingCerts
;
206 unsigned int certsDownloads
; ///< the number of downloaded missing certificates
209 /// successfully downloaded intermediate certificates (omitted by the peer)
210 Ssl::X509_STACK_Pointer downloadedCerts
;
213 /// outcome of the last (failed and) suspended negotiation attempt (or nil)
214 Security::IoResultPointer suspendedError_
;
216 JobWait
<Downloader
> certDownloadWait
; ///< waits for the missing certificate to be downloaded
219 } // namespace Security
221 #endif /* SQUID_SRC_SECURITY_PEERCONNECTOR_H */