1 /* 2 * Copyright (C) 1996-2021 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 "base/AsyncCbdataCalls.h" 14 #include "base/AsyncJob.h" 15 #include "CommCalls.h" 16 #include "http/forward.h" 17 #include "security/EncryptorAnswer.h" 18 #include "security/forward.h" 19 #if USE_OPENSSL 20 #include "ssl/support.h" 21 #endif 22 23 #include <iosfwd> 24 #include <queue> 25 26 class ErrorState; 27 class AccessLogEntry; 28 typedef RefCount<AccessLogEntry> AccessLogEntryPointer; 29 30 namespace Security 31 { 32 33 /** 34 * Initiates encryption on a connection to peers or servers. 35 * Despite its name does not perform any connect(2) operations. 36 * 37 * Contains common code and interfaces of various specialized PeerConnector's, 38 * including peer certificate validation code. 39 \par 40 * The caller receives a call back with Security::EncryptorAnswer. If answer.error 41 * is not nil, then there was an error and the encryption to the peer or server 42 * was not fully established. The error object is suitable for error response 43 * generation. 44 \par 45 * The caller must monitor the connection for closure because this 46 * job will not inform the caller about such events. 47 \par 48 * PeerConnector class currently supports a form of TLS negotiation timeout, 49 * which is accounted only when sets the read timeout from encrypted peers/servers. 50 * For a complete solution, the caller must monitor the overall connection 51 * establishment timeout and close the connection on timeouts. This is probably 52 * better than having dedicated (or none at all!) timeouts for peer selection, 53 * DNS lookup, TCP handshake, SSL handshake, etc. Some steps may have their 54 * own timeout, but not all steps should be forced to have theirs. 55 * XXX: tunnel.cc and probably other subsystems do not have an "overall 56 * connection establishment" timeout. We need to change their code so that they 57 * start monitoring earlier and close on timeouts. This change may need to be 58 * discussed on squid-dev. 59 \par 60 * This job never closes the connection, even on errors. If a 3rd-party 61 * closes the connection, this job simply quits without informing the caller. 62 */ 63 class PeerConnector: virtual public AsyncJob 64 { 65 CBDATA_CLASS(PeerConnector); 66 67 public: 68 typedef CbcPointer<PeerConnector> Pointer; 69 70 /// Callback dialer API to allow PeerConnector to set the answer. 71 class CbDialer 72 { 73 public: ~CbDialer()74 virtual ~CbDialer() {} 75 /// gives PeerConnector access to the in-dialer answer 76 virtual Security::EncryptorAnswer &answer() = 0; 77 }; 78 79 public: 80 PeerConnector(const Comm::ConnectionPointer &aServerConn, 81 AsyncCall::Pointer &aCallback, 82 const AccessLogEntryPointer &alp, 83 const time_t timeout = 0); 84 virtual ~PeerConnector(); 85 86 protected: 87 // AsyncJob API 88 virtual void start(); 89 virtual bool doneAll() const; 90 virtual void swanSong(); 91 virtual const char *status() const; 92 93 /// The comm_close callback handler. 94 void commCloseHandler(const CommCloseCbParams ¶ms); 95 96 /// Inform us that the connection is closed. Does the required clean-up. 97 void connectionClosed(const char *reason); 98 99 /// Sets up TCP socket-related notification callbacks if things go wrong. 100 /// If socket already closed return false, else install the comm_close 101 /// handler to monitor the socket. 102 bool prepareSocket(); 103 104 /// Sets the read timeout to avoid getting stuck while reading from a 105 /// silent server 106 void setReadTimeout(); 107 108 /// \returns true on successful TLS session initialization 109 virtual bool initialize(Security::SessionPointer &); 110 111 /// Performs a single secure connection negotiation step. 112 /// It is called multiple times untill the negotiation finishes or aborts. 113 void negotiate(); 114 115 /// Called after negotiation has finished. Cleans up TLS/SSL state. 116 /// Returns false if we are now waiting for the certs validation job. 117 /// Otherwise, returns true, regardless of negotiation success/failure. 118 bool sslFinalized(); 119 120 /// Called when the negotiation step aborted because data needs to 121 /// be transferred to/from server or on error. In the first case 122 /// setups the appropriate Comm::SetSelect handler. In second case 123 /// fill an error and report to the PeerConnector caller. 124 void handleNegotiateError(const int result); 125 126 /// Called when the openSSL SSL_connect fnction request more data from 127 /// the remote SSL server. Sets the read timeout and sets the 128 /// Squid COMM_SELECT_READ handler. 129 void noteWantRead(); 130 131 #if USE_OPENSSL 132 /// Run the certificates list sent by the SSL server and check if there 133 /// are missing certificates. Adds to the urlOfMissingCerts list the 134 /// URLS of missing certificates if this information provided by the 135 /// issued certificates with Authority Info Access extension. 136 bool checkForMissingCertificates(); 137 138 /// Start downloading procedure for the given URL. 139 void startCertDownloading(SBuf &url); 140 141 /// Called by Downloader after a certificate object downloaded. 142 void certDownloadingDone(SBuf &object, int status); 143 #endif 144 145 /// Called when the openSSL SSL_connect function needs to write data to 146 /// the remote SSL server. Sets the Squid COMM_SELECT_WRITE handler. 147 virtual void noteWantWrite(); 148 149 /// Called when the SSL_connect function aborts with an SSL negotiation error 150 /// \param result the SSL_connect return code 151 /// \param ssl_error the error code returned from the SSL_get_error function 152 /// \param ssl_lib_error the error returned from the ERR_Get_Error function 153 virtual void noteNegotiationError(const int result, const int ssl_error, const int ssl_lib_error); 154 155 /// Called when the SSL negotiation to the server completed and the certificates 156 /// validated using the cert validator. 157 /// \param error if not NULL the SSL negotiation was aborted with an error noteNegotiationDone(ErrorState * error)158 virtual void noteNegotiationDone(ErrorState *error) {} 159 160 /// Must implemented by the kid classes to return the TLS context object to use 161 /// for building the encryption context objects. 162 virtual Security::ContextPointer getTlsContext() = 0; 163 164 /// mimics FwdState to minimize changes to FwdState::initiate/negotiateSsl serverConnection()165 Comm::ConnectionPointer const &serverConnection() const { return serverConn; } 166 167 void bail(ErrorState *error); ///< Return an error to the PeerConnector caller 168 169 /// Callback the caller class, and pass the ready to communicate secure 170 /// connection or an error if PeerConnector failed. 171 void callBack(); 172 173 /// If called the certificates validator will not used bypassCertValidator()174 void bypassCertValidator() {useCertValidator_ = false;} 175 176 /// Called after negotiation finishes to record connection details for 177 /// logging 178 void recordNegotiationDetails(); 179 180 HttpRequestPointer request; ///< peer connection trigger or cause 181 Comm::ConnectionPointer serverConn; ///< TCP connection to the peer 182 AccessLogEntryPointer al; ///< info for the future access.log entry 183 AsyncCall::Pointer callback; ///< we call this with the results 184 private: 185 PeerConnector(const PeerConnector &); // not implemented 186 PeerConnector &operator =(const PeerConnector &); // not implemented 187 188 #if USE_OPENSSL 189 /// Process response from cert validator helper 190 void sslCrtvdHandleReply(Ssl::CertValidationResponsePointer); 191 192 /// Check SSL errors returned from cert validator against sslproxy_cert_error access list 193 Security::CertErrors *sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &, Ssl::ErrorDetail *&); 194 #endif 195 196 static void NegotiateSsl(int fd, void *data); 197 void negotiateSsl(); 198 199 /// The maximum allowed missing certificates downloads. 200 static const unsigned int MaxCertsDownloads = 10; 201 /// The maximum allowed nested certificates downloads. 202 static const unsigned int MaxNestedDownloads = 3; 203 204 AsyncCall::Pointer closeHandler; ///< we call this when the connection closed 205 time_t negotiationTimeout; ///< the SSL connection timeout to use 206 time_t startTime; ///< when the peer connector negotiation started 207 bool useCertValidator_; ///< whether the certificate validator should bypassed 208 /// The list of URLs where missing certificates should be downloaded. 209 std::queue<SBuf> urlsOfMissingCerts; 210 unsigned int certsDownloads; ///< the number of downloaded missing certificates 211 }; 212 213 } // namespace Security 214 215 #endif /* SQUID_SRC_SECURITY_PEERCONNECTOR_H */ 216 217