]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/PeekingPeerConnector.cc
Minimize direct comparisons with ACCESS_ALLOWED and ACCESS_DENIED.
[thirdparty/squid.git] / src / ssl / PeekingPeerConnector.cc
CommitLineData
32f1ca3f 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
32f1ca3f
AJ
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/* DEBUG: section 83 SSL-Bump Server/Peer negotiation */
10
11#include "squid.h"
12#include "acl/FilledChecklist.h"
13#include "client_side.h"
14#include "errorpage.h"
15#include "fde.h"
0ba8b2ad 16#include "http/Stream.h"
64d0dd9f 17#include "HttpRequest.h"
32f1ca3f
AJ
18#include "security/NegotiationHistory.h"
19#include "SquidConfig.h"
20#include "ssl/bio.h"
21#include "ssl/PeekingPeerConnector.h"
22#include "ssl/ServerBump.h"
23
24CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeekingPeerConnector);
25
26void switchToTunnel(HttpRequest *request, Comm::ConnectionPointer & clientConn, Comm::ConnectionPointer &srvConn);
27
28void
29Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone(allow_t answer, void *data)
30{
31 Ssl::PeekingPeerConnector *peerConnect = (Ssl::PeekingPeerConnector *) data;
32 // Use job calls to add done() checks and other job logic/protections.
33 CallJobHere1(83, 7, CbcPointer<PeekingPeerConnector>(peerConnect), Ssl::PeekingPeerConnector, checkForPeekAndSpliceDone, answer);
34}
35
36void
37Ssl::PeekingPeerConnector::checkForPeekAndSpliceDone(allow_t answer)
38{
06bf5384 39 const Ssl::BumpMode finalAction = answer.allowed() ?
32f1ca3f
AJ
40 static_cast<Ssl::BumpMode>(answer.kind):
41 checkForPeekAndSpliceGuess();
42 checkForPeekAndSpliceMatched(finalAction);
43}
44
45void
46Ssl::PeekingPeerConnector::checkForPeekAndSplice()
47{
48 // Mark Step3 of bumping
49 if (request->clientConnectionManager.valid()) {
50 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
51 serverBump->step = Ssl::bumpStep3;
52 }
53 }
54
55 handleServerCertificate();
56
57 ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(
58 ::Config.accessList.ssl_bump,
59 request.getRaw(), NULL);
d4ddb3e6 60 acl_checklist->al = al;
32f1ca3f
AJ
61 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpNone));
62 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpPeek));
63 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpStare));
64 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpClientFirst));
65 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpServerFirst));
ad23e748
AJ
66 Security::SessionPointer session(fd_table[serverConn->fd].ssl);
67 BIO *b = SSL_get_rbio(session.get());
093deea9 68 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
32f1ca3f
AJ
69 if (!srvBio->canSplice())
70 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpSplice));
71 if (!srvBio->canBump())
72 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpBump));
73 acl_checklist->nonBlockingCheck(Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone, this);
74}
75
76void
77Ssl::PeekingPeerConnector::checkForPeekAndSpliceMatched(const Ssl::BumpMode action)
78{
ad23e748
AJ
79 Security::SessionPointer session(fd_table[serverConn->fd].ssl);
80 BIO *b = SSL_get_rbio(session.get());
093deea9 81 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
32f1ca3f
AJ
82 debugs(83,5, "Will check for peek and splice on FD " << serverConn->fd);
83
84 Ssl::BumpMode finalAction = action;
85 Must(finalAction == Ssl::bumpSplice || finalAction == Ssl::bumpBump || finalAction == Ssl::bumpTerminate);
86 // Record final decision
87 if (request->clientConnectionManager.valid()) {
88 request->clientConnectionManager->sslBumpMode = finalAction;
89 request->clientConnectionManager->serverBump()->act.step3 = finalAction;
90 }
bf352fb2 91 al->ssl.bumpMode = finalAction;
32f1ca3f
AJ
92
93 if (finalAction == Ssl::bumpTerminate) {
94 serverConn->close();
95 clientConn->close();
96 } else if (finalAction != Ssl::bumpSplice) {
97 //Allow write, proceed with the connection
98 srvBio->holdWrite(false);
99 srvBio->recordInput(false);
100 debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn->fd);
a72b6e88 101 Security::PeerConnector::noteWantWrite();
32f1ca3f
AJ
102 } else {
103 splice = true;
104 // Ssl Negotiation stops here. Last SSL checks for valid certificates
105 // and if done, switch to tunnel mode
106 if (sslFinalized()) {
107 debugs(83,5, "Abort NegotiateSSL on FD " << serverConn->fd << " and splice the connection");
56753478 108 callBack();
32f1ca3f
AJ
109 }
110 }
111}
112
113Ssl::BumpMode
114Ssl::PeekingPeerConnector::checkForPeekAndSpliceGuess() const
115{
116 if (const ConnStateData *csd = request->clientConnectionManager.valid()) {
117 const Ssl::BumpMode currentMode = csd->sslBumpMode;
118 if (currentMode == Ssl::bumpStare) {
119 debugs(83,5, "default to bumping after staring");
120 return Ssl::bumpBump;
121 }
122 debugs(83,5, "default to splicing after " << currentMode);
123 } else {
124 debugs(83,3, "default to splicing due to missing info");
125 }
126
127 return Ssl::bumpSplice;
128}
129
b23f5f9c
AJ
130Security::ContextPointer
131Ssl::PeekingPeerConnector::getTlsContext()
32f1ca3f 132{
b23f5f9c 133 return ::Config.ssl_client.sslContext;
32f1ca3f
AJ
134}
135
eba8d9bb 136bool
0166128b 137Ssl::PeekingPeerConnector::initialize(Security::SessionPointer &serverSession)
32f1ca3f 138{
0166128b 139 if (!Security::PeerConnector::initialize(serverSession))
eba8d9bb 140 return false;
32f1ca3f
AJ
141
142 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
143
144 // client connection is required in the case we need to splice
145 // or terminate client and server connections
146 assert(clientConn != NULL);
147 SBuf *hostName = NULL;
32f1ca3f 148
eba8d9bb
AJ
149 //Enable Status_request TLS extension, required to bump some clients
150 SSL_set_tlsext_status_type(serverSession.get(), TLSEXT_STATUSTYPE_ocsp);
32f1ca3f 151
3cae14a6 152 const Security::TlsDetails::Pointer details = csd->tlsParser.details;
49a4d72f 153 if (details && !details->serverName.isEmpty())
3cae14a6 154 hostName = new SBuf(details->serverName);
32f1ca3f
AJ
155
156 if (!hostName) {
157 // While we are peeking at the certificate, we may not know the server
158 // name that the client will request (after interception or CONNECT)
159 // unless it was the CONNECT request with a user-typed address.
160 const bool isConnectRequest = !csd->port->flags.isIntercepted();
161 if (!request->flags.sslPeek || isConnectRequest)
162 hostName = new SBuf(request->url.host());
163 }
164
165 if (hostName)
eba8d9bb 166 SSL_set_ex_data(serverSession.get(), ssl_ex_index_server, (void*)hostName);
32f1ca3f
AJ
167
168 Must(!csd->serverBump() || csd->serverBump()->step <= Ssl::bumpStep2);
169 if (csd->sslBumpMode == Ssl::bumpPeek || csd->sslBumpMode == Ssl::bumpStare) {
eba8d9bb
AJ
170 auto clientSession = fd_table[clientConn->fd].ssl.get();
171 Must(clientSession);
172 BIO *bc = SSL_get_rbio(clientSession);
093deea9 173 Ssl::ClientBio *cltBio = static_cast<Ssl::ClientBio *>(BIO_get_data(bc));
3cae14a6 174 Must(cltBio);
6744c1a8 175 if (details && details->tlsVersion.protocol != AnyP::PROTO_NONE)
eba8d9bb 176 applyTlsDetailsToSSL(serverSession.get(), details, csd->sslBumpMode);
6744c1a8
CT
177
178 BIO *b = SSL_get_rbio(serverSession.get());
179 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
180 Must(srvBio);
181 // inherit client features such as TLS version and SNI
182 srvBio->setClientFeatures(details, cltBio->rBufData());
183 srvBio->recordInput(true);
184 srvBio->mode(csd->sslBumpMode);
32f1ca3f
AJ
185 } else {
186 // Set client SSL options
eba8d9bb 187 SSL_set_options(serverSession.get(), ::Security::ProxyOutgoingConfig.parsedOptions);
32f1ca3f
AJ
188
189 // Use SNI TLS extension only when we connect directly
190 // to the origin server and we know the server host name.
191 const char *sniServer = NULL;
192 const bool redirected = request->flags.redirected && ::Config.onoff.redir_rewrites_host;
193 if (!hostName || redirected)
194 sniServer = !request->url.hostIsNumeric() ? request->url.host() : NULL;
195 else
196 sniServer = hostName->c_str();
197
198 if (sniServer)
eba8d9bb 199 Ssl::setClientSNI(serverSession.get(), sniServer);
32f1ca3f
AJ
200 }
201
088f0761 202 if (Ssl::ServerBump *serverBump = csd->serverBump()) {
8f917129 203 serverBump->attachServerSession(serverSession);
088f0761
CT
204 // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
205 if (X509 *peeked_cert = serverBump->serverCert.get()) {
6f2b8700 206 X509_up_ref(peeked_cert);
eba8d9bb 207 SSL_set_ex_data(serverSession.get(), ssl_ex_index_ssl_peeked_cert, peeked_cert);
088f0761 208 }
32f1ca3f
AJ
209 }
210 }
211
eba8d9bb 212 return true;
32f1ca3f
AJ
213}
214
215void
216Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState *error)
217{
32f1ca3f 218 // Check the list error with
ad23e748 219 if (!request->clientConnectionManager.valid() || !fd_table[serverConnection()->fd].ssl)
32f1ca3f
AJ
220 return;
221
222 // remember the server certificate from the ErrorDetail object
223 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
32f1ca3f
AJ
224 if (!serverBump->serverCert.get()) {
225 // remember the server certificate from the ErrorDetail object
226 if (error && error->detail && error->detail->peerCert())
014a9017 227 serverBump->serverCert.resetAndLock(error->detail->peerCert());
32f1ca3f
AJ
228 else {
229 handleServerCertificate();
230 }
231 }
232
233 if (error) {
234 // For intercepted connections, set the host name to the server
235 // certificate CN. Otherwise, we just hope that CONNECT is using
236 // a user-entered address (a host name or a user-entered IP).
237 const bool isConnectRequest = !request->clientConnectionManager->port->flags.isIntercepted();
238 if (request->flags.sslPeek && !isConnectRequest) {
239 if (X509 *srvX509 = serverBump->serverCert.get()) {
240 if (const char *name = Ssl::CommonHostName(srvX509)) {
241 request->url.host(name);
242 debugs(83, 3, "reset request host: " << name);
243 }
244 }
245 }
246 }
247 }
248
32f1ca3f
AJ
249 if (!error) {
250 serverCertificateVerified();
251 if (splice) {
32f1ca3f 252 switchToTunnel(request.getRaw(), clientConn, serverConn);
56753478 253 tunnelInsteadOfNegotiating();
32f1ca3f
AJ
254 }
255 }
256}
257
258void
259Ssl::PeekingPeerConnector::noteWantWrite()
260{
261 const int fd = serverConnection()->fd;
ad23e748
AJ
262 Security::SessionPointer session(fd_table[fd].ssl);
263 BIO *b = SSL_get_rbio(session.get());
093deea9 264 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
32f1ca3f
AJ
265
266 if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
bc8e1f18 267 debugs(81, 3, "hold write on SSL connection on FD " << fd);
32f1ca3f
AJ
268 checkForPeekAndSplice();
269 return;
270 }
271
a72b6e88 272 Security::PeerConnector::noteWantWrite();
32f1ca3f
AJ
273}
274
275void
0166128b 276Ssl::PeekingPeerConnector::noteNegotiationError(const int result, const int ssl_error, const int ssl_lib_error)
32f1ca3f
AJ
277{
278 const int fd = serverConnection()->fd;
ad23e748
AJ
279 Security::SessionPointer session(fd_table[fd].ssl);
280 BIO *b = SSL_get_rbio(session.get());
093deea9 281 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
32f1ca3f
AJ
282
283 // In Peek mode, the ClientHello message sent to the server. If the
284 // server resuming a previous (spliced) SSL session with the client,
285 // then probably we are here because local SSL object does not know
286 // anything about the session being resumed.
287 //
288 if (srvBio->bumpMode() == Ssl::bumpPeek && (resumingSession = srvBio->resumingSession())) {
289 // we currently splice all resumed sessions unconditionally
290 if (const bool spliceResumed = true) {
291 bypassCertValidator();
292 checkForPeekAndSpliceMatched(Ssl::bumpSplice);
293 return;
294 } // else fall through to find a matching ssl_bump action (with limited info)
295 }
296
297 // If we are in peek-and-splice mode and still we did not write to
298 // server yet, try to see if we should splice.
299 // In this case the connection can be saved.
300 // If the checklist decision is do not splice a new error will
301 // occur in the next SSL_connect call, and we will fail again.
302 // Abort on certificate validation errors to avoid splicing and
303 // thus hiding them.
304 // Abort if no certificate found probably because of malformed or
305 // unsupported server Hello message (TODO: make configurable).
ad23e748 306 if (!SSL_get_ex_data(session.get(), ssl_ex_index_ssl_error_detail) &&
32f1ca3f 307 (srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
ad23e748
AJ
308 Security::CertPointer serverCert(SSL_get_peer_certificate(session.get()));
309 if (serverCert) {
ea574635 310 debugs(81, 3, "Error (" << Security::ErrorString(ssl_lib_error) << ") but, hold write on SSL connection on FD " << fd);
32f1ca3f
AJ
311 checkForPeekAndSplice();
312 return;
313 }
314 }
315
316 // else call parent noteNegotiationError to produce an error page
0166128b 317 Security::PeerConnector::noteNegotiationError(result, ssl_error, ssl_lib_error);
32f1ca3f
AJ
318}
319
320void
321Ssl::PeekingPeerConnector::handleServerCertificate()
322{
323 if (serverCertificateHandled)
324 return;
325
326 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
327 const int fd = serverConnection()->fd;
ad23e748
AJ
328 Security::SessionPointer session(fd_table[fd].ssl);
329 Security::CertPointer serverCert(SSL_get_peer_certificate(session.get()));
330 if (!serverCert)
32f1ca3f
AJ
331 return;
332
333 serverCertificateHandled = true;
334
335 // remember the server certificate for later use
336 if (Ssl::ServerBump *serverBump = csd->serverBump()) {
35b3559c 337 serverBump->serverCert = std::move(serverCert);
32f1ca3f
AJ
338 }
339 }
340}
341
342void
343Ssl::PeekingPeerConnector::serverCertificateVerified()
344{
345 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
346 Security::CertPointer serverCert;
347 if(Ssl::ServerBump *serverBump = csd->serverBump())
014a9017 348 serverCert.resetAndLock(serverBump->serverCert.get());
32f1ca3f
AJ
349 else {
350 const int fd = serverConnection()->fd;
ad23e748
AJ
351 Security::SessionPointer session(fd_table[fd].ssl);
352 serverCert.resetWithoutLocking(SSL_get_peer_certificate(session.get()));
32f1ca3f 353 }
ad23e748 354 if (serverCert) {
32f1ca3f
AJ
355 csd->resetSslCommonName(Ssl::CommonHostName(serverCert.get()));
356 debugs(83, 5, "HTTPS server CN: " << csd->sslCommonName() <<
357 " bumped: " << *serverConnection());
358 }
359 }
360}
361
56753478
CT
362void
363Ssl::PeekingPeerConnector::tunnelInsteadOfNegotiating()
364{
365 Must(callback != NULL);
366 CbDialer *dialer = dynamic_cast<CbDialer*>(callback->getDialer());
367 Must(dialer);
368 dialer->answer().tunneled = true;
369 debugs(83, 5, "The SSL negotiation with server aborted");
370}
371