]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2025 The Squid Software Foundation and contributors | |
3 | * | |
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. | |
7 | */ | |
8 | ||
9 | #ifndef SQUID_SRC_SECURITY_PEERCONNECTOR_H | |
10 | #define SQUID_SRC_SECURITY_PEERCONNECTOR_H | |
11 | ||
12 | #include "acl/Acl.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" | |
22 | #if USE_OPENSSL | |
23 | #include "ssl/support.h" | |
24 | #endif | |
25 | ||
26 | #include <iosfwd> | |
27 | #include <queue> | |
28 | ||
29 | class Downloader; | |
30 | class DownloaderAnswer; | |
31 | class AccessLogEntry; | |
32 | typedef RefCount<AccessLogEntry> AccessLogEntryPointer; | |
33 | ||
34 | namespace Security | |
35 | { | |
36 | ||
37 | class IoResult; | |
38 | typedef RefCount<IoResult> IoResultPointer; | |
39 | ||
40 | /** | |
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. | |
44 | * | |
45 | * Contains common code and interfaces of various specialized PeerConnector's, | |
46 | * including peer certificate validation code. | |
47 | */ | |
48 | class PeerConnector: virtual public AsyncJob, public Acl::ChecklistFiller | |
49 | { | |
50 | CBDATA_INTERMEDIATE(); | |
51 | ||
52 | public: | |
53 | typedef CbcPointer<PeerConnector> Pointer; | |
54 | ||
55 | PeerConnector(const Comm::ConnectionPointer &aServerConn, | |
56 | const AsyncCallback<EncryptorAnswer> &, | |
57 | const AccessLogEntryPointer &alp, | |
58 | const time_t timeout = 0); | |
59 | ~PeerConnector() override; | |
60 | ||
61 | /// hack: whether the connection requires fwdPconnPool->noteUses() | |
62 | bool noteFwdPconnUse; | |
63 | ||
64 | protected: | |
65 | // AsyncJob API | |
66 | void start() override; | |
67 | bool doneAll() const override; | |
68 | void swanSong() override; | |
69 | const char *status() const override; | |
70 | ||
71 | /* Acl::ChecklistFiller API */ | |
72 | void fillChecklist(ACLFilledChecklist &) const override; | |
73 | ||
74 | /// The connection read timeout callback handler. | |
75 | void commTimeoutHandler(const CommTimeoutCbParams &); | |
76 | ||
77 | /// The comm_close callback handler. | |
78 | void commCloseHandler(const CommCloseCbParams ¶ms); | |
79 | ||
80 | /// \returns true on successful TLS session initialization | |
81 | virtual bool initialize(Security::SessionPointer &); | |
82 | ||
83 | /// Performs a single secure connection negotiation step. | |
84 | /// It is called multiple times until the negotiation finishes or aborts. | |
85 | void negotiate(); | |
86 | ||
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. | |
90 | bool sslFinalized(); | |
91 | ||
92 | /// Called after each negotiation step to handle the result | |
93 | void handleNegotiationResult(const Security::IoResult &); | |
94 | ||
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. | |
98 | void noteWantRead(); | |
99 | ||
100 | /// Whether TLS negotiation has been paused and not yet resumed | |
101 | bool isSuspended() const { return static_cast<bool>(suspendedError_); } | |
102 | ||
103 | #if USE_OPENSSL | |
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); | |
107 | ||
108 | /// Resumes TLS negotiation paused by suspendNegotiation() | |
109 | void resumeNegotiation(); | |
110 | ||
111 | /// Either initiates fetching of missing certificates or bails with an error | |
112 | void handleMissingCertificates(const Security::IoResult &lastError); | |
113 | ||
114 | /// Start downloading procedure for the given URL. | |
115 | void startCertDownloading(SBuf &url); | |
116 | ||
117 | /// Called by Downloader after a certificate object downloaded. | |
118 | void certDownloadingDone(DownloaderAnswer &); | |
119 | #endif | |
120 | ||
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(); | |
124 | ||
125 | /// Called when the SSL_connect function aborts with an SSL negotiation error | |
126 | virtual void noteNegotiationError(const Security::ErrorDetailPointer &); | |
127 | ||
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 *) {} | |
132 | ||
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; | |
136 | ||
137 | /// mimics FwdState to minimize changes to FwdState::initiate/negotiateSsl | |
138 | Comm::ConnectionPointer const &serverConnection() const { return serverConn; } | |
139 | ||
140 | /// sends the given error to the initiator | |
141 | void bail(ErrorState *error); | |
142 | ||
143 | /// sends the encrypted connection to the initiator | |
144 | void sendSuccess(); | |
145 | ||
146 | /// a bail(), sendSuccess() helper: sends results to the initiator | |
147 | void callBack(); | |
148 | ||
149 | /// a bail(), sendSuccess() helper: stops monitoring the connection | |
150 | void disconnect(); | |
151 | ||
152 | /// updates connection usage history before the connection is closed | |
153 | void countFailingConnection(); | |
154 | ||
155 | /// If called the certificates validator will not used | |
156 | void bypassCertValidator() {useCertValidator_ = false;} | |
157 | ||
158 | /// Called after negotiation finishes to record connection details for | |
159 | /// logging | |
160 | void recordNegotiationDetails(); | |
161 | ||
162 | /// convenience method to get to the answer fields | |
163 | EncryptorAnswer &answer(); | |
164 | ||
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 | |
168 | ||
169 | /// answer destination | |
170 | AsyncCallback<EncryptorAnswer> callback; | |
171 | ||
172 | private: | |
173 | PeerConnector(const PeerConnector &); // not implemented | |
174 | PeerConnector &operator =(const PeerConnector &); // not implemented | |
175 | ||
176 | #if USE_OPENSSL | |
177 | unsigned int certDownloadNestingLevel() const; | |
178 | ||
179 | /// Process response from cert validator helper | |
180 | void sslCrtvdHandleReply(Ssl::CertValidationResponsePointer &); | |
181 | ||
182 | /// Check SSL errors returned from cert validator against sslproxy_cert_error access list | |
183 | Security::CertErrors *sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &, ErrorDetailPointer &); | |
184 | ||
185 | bool computeMissingCertificateUrls(const Connection &); | |
186 | #endif | |
187 | ||
188 | static void NegotiateSsl(int fd, void *data); | |
189 | void negotiateSsl(); | |
190 | ||
191 | /// The maximum number of missing certificates a single PeerConnector may download | |
192 | static const unsigned int MaxCertsDownloads = 10; | |
193 | ||
194 | /// The maximum number of inter-dependent Downloader jobs a worker may initiate | |
195 | static const unsigned int MaxNestedDownloads = 3; | |
196 | ||
197 | /// managers logging of the being-established TLS connection secrets | |
198 | Security::KeyLogger keyLogger; | |
199 | ||
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 | |
207 | ||
208 | #if USE_OPENSSL | |
209 | /// successfully downloaded intermediate certificates (omitted by the peer) | |
210 | Ssl::X509_STACK_Pointer downloadedCerts; | |
211 | #endif | |
212 | ||
213 | /// outcome of the last (failed and) suspended negotiation attempt (or nil) | |
214 | Security::IoResultPointer suspendedError_; | |
215 | ||
216 | JobWait<Downloader> certDownloadWait; ///< waits for the missing certificate to be downloaded | |
217 | }; | |
218 | ||
219 | } // namespace Security | |
220 | ||
221 | #endif /* SQUID_SRC_SECURITY_PEERCONNECTOR_H */ | |
222 |