]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/PeekingPeerConnector.cc
BUG: Unexpected state while connecting to ... server, part 2 (#917)
[thirdparty/squid.git] / src / ssl / PeekingPeerConnector.cc
CommitLineData
32f1ca3f 1/*
f70aedc4 2 * Copyright (C) 1996-2021 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"
83b053a0 18#include "security/ErrorDetail.h"
32f1ca3f
AJ
19#include "security/NegotiationHistory.h"
20#include "SquidConfig.h"
21#include "ssl/bio.h"
22#include "ssl/PeekingPeerConnector.h"
23#include "ssl/ServerBump.h"
8b082ed9 24#include "tunnel.h"
32f1ca3f
AJ
25
26CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeekingPeerConnector);
27
4647c8bd
CT
28Ssl::PeekingPeerConnector::PeekingPeerConnector(HttpRequestPointer &aRequest,
29 const Comm::ConnectionPointer &aServerConn,
30 const Comm::ConnectionPointer &aClientConn,
31 AsyncCall::Pointer &aCallback,
32 const AccessLogEntryPointer &alp,
33 const time_t timeout):
34 AsyncJob("Ssl::PeekingPeerConnector"),
35 Security::PeerConnector(aServerConn, aCallback, alp, timeout),
36 clientConn(aClientConn),
37 splice(false),
38 serverCertificateHandled(false)
39{
40 request = aRequest;
41
42 if (const auto csd = request->clientConnectionManager.valid()) {
43 const auto serverBump = csd->serverBump();
44 Must(serverBump);
45 Must(serverBump->at(XactionStep::tlsBump3));
46 }
47 // else the client is gone, and we cannot check the step, but must carry on
48}
49
32f1ca3f 50void
2b6b1bcb 51Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone(const Acl::Answer aclAnswer, void *data)
32f1ca3f
AJ
52{
53 Ssl::PeekingPeerConnector *peerConnect = (Ssl::PeekingPeerConnector *) data;
54 // Use job calls to add done() checks and other job logic/protections.
2b6b1bcb 55 CallJobHere1(83, 7, CbcPointer<PeekingPeerConnector>(peerConnect), Ssl::PeekingPeerConnector, checkForPeekAndSpliceDone, aclAnswer);
32f1ca3f
AJ
56}
57
58void
2b6b1bcb 59Ssl::PeekingPeerConnector::checkForPeekAndSpliceDone(const Acl::Answer aclAnswer)
32f1ca3f 60{
2b6b1bcb
AR
61 const Ssl::BumpMode finalAction = aclAnswer.allowed() ?
62 static_cast<Ssl::BumpMode>(aclAnswer.kind):
32f1ca3f
AJ
63 checkForPeekAndSpliceGuess();
64 checkForPeekAndSpliceMatched(finalAction);
65}
66
67void
68Ssl::PeekingPeerConnector::checkForPeekAndSplice()
69{
32f1ca3f
AJ
70 handleServerCertificate();
71
72 ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(
73 ::Config.accessList.ssl_bump,
74 request.getRaw(), NULL);
d4ddb3e6 75 acl_checklist->al = al;
329c128c 76 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpNone));
77 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpPeek));
78 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpStare));
79 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpClientFirst));
80 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpServerFirst));
ad23e748
AJ
81 Security::SessionPointer session(fd_table[serverConn->fd].ssl);
82 BIO *b = SSL_get_rbio(session.get());
093deea9 83 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
32f1ca3f 84 if (!srvBio->canSplice())
329c128c 85 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpSplice));
32f1ca3f 86 if (!srvBio->canBump())
329c128c 87 acl_checklist->banAction(Acl::Answer(ACCESS_ALLOWED, Ssl::bumpBump));
cb365059 88 acl_checklist->syncAle(request.getRaw(), nullptr);
32f1ca3f
AJ
89 acl_checklist->nonBlockingCheck(Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone, this);
90}
91
92void
93Ssl::PeekingPeerConnector::checkForPeekAndSpliceMatched(const Ssl::BumpMode action)
94{
ad23e748
AJ
95 Security::SessionPointer session(fd_table[serverConn->fd].ssl);
96 BIO *b = SSL_get_rbio(session.get());
093deea9 97 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
32f1ca3f
AJ
98 debugs(83,5, "Will check for peek and splice on FD " << serverConn->fd);
99
100 Ssl::BumpMode finalAction = action;
101 Must(finalAction == Ssl::bumpSplice || finalAction == Ssl::bumpBump || finalAction == Ssl::bumpTerminate);
102 // Record final decision
103 if (request->clientConnectionManager.valid()) {
104 request->clientConnectionManager->sslBumpMode = finalAction;
105 request->clientConnectionManager->serverBump()->act.step3 = finalAction;
106 }
bf352fb2 107 al->ssl.bumpMode = finalAction;
32f1ca3f
AJ
108
109 if (finalAction == Ssl::bumpTerminate) {
25b0ce45 110 bail(new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scForbidden, request.getRaw(), al));
32f1ca3f 111 clientConn->close();
25b0ce45 112 clientConn = nullptr;
32f1ca3f
AJ
113 } else if (finalAction != Ssl::bumpSplice) {
114 //Allow write, proceed with the connection
115 srvBio->holdWrite(false);
116 srvBio->recordInput(false);
117 debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn->fd);
a72b6e88 118 Security::PeerConnector::noteWantWrite();
32f1ca3f
AJ
119 } else {
120 splice = true;
121 // Ssl Negotiation stops here. Last SSL checks for valid certificates
122 // and if done, switch to tunnel mode
2b6b1bcb 123 if (sslFinalized() && callback)
56753478 124 callBack();
32f1ca3f
AJ
125 }
126}
127
128Ssl::BumpMode
129Ssl::PeekingPeerConnector::checkForPeekAndSpliceGuess() const
130{
131 if (const ConnStateData *csd = request->clientConnectionManager.valid()) {
132 const Ssl::BumpMode currentMode = csd->sslBumpMode;
133 if (currentMode == Ssl::bumpStare) {
134 debugs(83,5, "default to bumping after staring");
135 return Ssl::bumpBump;
136 }
137 debugs(83,5, "default to splicing after " << currentMode);
138 } else {
139 debugs(83,3, "default to splicing due to missing info");
140 }
141
142 return Ssl::bumpSplice;
143}
144
b23f5f9c
AJ
145Security::ContextPointer
146Ssl::PeekingPeerConnector::getTlsContext()
32f1ca3f 147{
b23f5f9c 148 return ::Config.ssl_client.sslContext;
32f1ca3f
AJ
149}
150
eba8d9bb 151bool
0166128b 152Ssl::PeekingPeerConnector::initialize(Security::SessionPointer &serverSession)
32f1ca3f 153{
0166128b 154 if (!Security::PeerConnector::initialize(serverSession))
eba8d9bb 155 return false;
32f1ca3f 156
25b0ce45
CT
157 // client connection supplies TLS client details and is also used if we
158 // need to splice or terminate the client and server connections
159 if (!Comm::IsConnOpen(clientConn))
160 return false;
161
32f1ca3f
AJ
162 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
163
32f1ca3f 164 SBuf *hostName = NULL;
32f1ca3f 165
eba8d9bb
AJ
166 //Enable Status_request TLS extension, required to bump some clients
167 SSL_set_tlsext_status_type(serverSession.get(), TLSEXT_STATUSTYPE_ocsp);
32f1ca3f 168
3cae14a6 169 const Security::TlsDetails::Pointer details = csd->tlsParser.details;
49a4d72f 170 if (details && !details->serverName.isEmpty())
3cae14a6 171 hostName = new SBuf(details->serverName);
32f1ca3f
AJ
172
173 if (!hostName) {
174 // While we are peeking at the certificate, we may not know the server
175 // name that the client will request (after interception or CONNECT)
176 // unless it was the CONNECT request with a user-typed address.
177 const bool isConnectRequest = !csd->port->flags.isIntercepted();
178 if (!request->flags.sslPeek || isConnectRequest)
179 hostName = new SBuf(request->url.host());
180 }
181
182 if (hostName)
eba8d9bb 183 SSL_set_ex_data(serverSession.get(), ssl_ex_index_server, (void*)hostName);
32f1ca3f 184
32f1ca3f 185 if (csd->sslBumpMode == Ssl::bumpPeek || csd->sslBumpMode == Ssl::bumpStare) {
eba8d9bb
AJ
186 auto clientSession = fd_table[clientConn->fd].ssl.get();
187 Must(clientSession);
188 BIO *bc = SSL_get_rbio(clientSession);
093deea9 189 Ssl::ClientBio *cltBio = static_cast<Ssl::ClientBio *>(BIO_get_data(bc));
3cae14a6 190 Must(cltBio);
6744c1a8 191 if (details && details->tlsVersion.protocol != AnyP::PROTO_NONE)
eba8d9bb 192 applyTlsDetailsToSSL(serverSession.get(), details, csd->sslBumpMode);
6744c1a8
CT
193
194 BIO *b = SSL_get_rbio(serverSession.get());
195 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
196 Must(srvBio);
197 // inherit client features such as TLS version and SNI
198 srvBio->setClientFeatures(details, cltBio->rBufData());
199 srvBio->recordInput(true);
200 srvBio->mode(csd->sslBumpMode);
32f1ca3f
AJ
201 } else {
202 // Set client SSL options
b491f761 203 ::Security::ProxyOutgoingConfig.updateSessionOptions(serverSession);
32f1ca3f 204
32f1ca3f 205 const bool redirected = request->flags.redirected && ::Config.onoff.redir_rewrites_host;
428819f3
RB
206 const char *sniServer = (!hostName || redirected) ?
207 request->url.host() :
208 hostName->c_str();
32f1ca3f 209 if (sniServer)
428819f3 210 setClientSNI(serverSession.get(), sniServer);
32f1ca3f
AJ
211 }
212
088f0761 213 if (Ssl::ServerBump *serverBump = csd->serverBump()) {
8f917129 214 serverBump->attachServerSession(serverSession);
088f0761
CT
215 // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
216 if (X509 *peeked_cert = serverBump->serverCert.get()) {
6f2b8700 217 X509_up_ref(peeked_cert);
eba8d9bb 218 SSL_set_ex_data(serverSession.get(), ssl_ex_index_ssl_peeked_cert, peeked_cert);
088f0761 219 }
32f1ca3f
AJ
220 }
221 }
222
eba8d9bb 223 return true;
32f1ca3f
AJ
224}
225
226void
227Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState *error)
228{
32f1ca3f 229 // Check the list error with
ad23e748 230 if (!request->clientConnectionManager.valid() || !fd_table[serverConnection()->fd].ssl)
32f1ca3f
AJ
231 return;
232
233 // remember the server certificate from the ErrorDetail object
234 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
32f1ca3f
AJ
235 if (!serverBump->serverCert.get()) {
236 // remember the server certificate from the ErrorDetail object
83b053a0
CT
237 const auto errDetail = dynamic_cast<Security::ErrorDetail *>(error ? error->detail.getRaw() : nullptr);
238 if (errDetail && errDetail->peerCert())
239 serverBump->serverCert.resetAndLock(errDetail->peerCert());
32f1ca3f
AJ
240 else {
241 handleServerCertificate();
242 }
243 }
244
245 if (error) {
246 // For intercepted connections, set the host name to the server
247 // certificate CN. Otherwise, we just hope that CONNECT is using
248 // a user-entered address (a host name or a user-entered IP).
249 const bool isConnectRequest = !request->clientConnectionManager->port->flags.isIntercepted();
250 if (request->flags.sslPeek && !isConnectRequest) {
251 if (X509 *srvX509 = serverBump->serverCert.get()) {
252 if (const char *name = Ssl::CommonHostName(srvX509)) {
253 request->url.host(name);
254 debugs(83, 3, "reset request host: " << name);
255 }
256 }
257 }
258 }
259 }
260
32f1ca3f
AJ
261 if (!error) {
262 serverCertificateVerified();
263 if (splice) {
25b0ce45
CT
264 if (!Comm::IsConnOpen(clientConn)) {
265 bail(new ErrorState(ERR_GATEWAY_FAILURE, Http::scInternalServerError, request.getRaw(), al));
266 throw TextException("from-client connection gone", Here());
267 }
1c2b4465 268 startTunneling();
32f1ca3f
AJ
269 }
270 }
271}
272
1c2b4465
CT
273void
274Ssl::PeekingPeerConnector::startTunneling()
275{
276 // switchToTunnel() drains any already buffered from-server data (rBufData)
277 fd_table[serverConn->fd].useDefaultIo();
278 // tunnelStartShoveling() drains any buffered from-client data (inBuf)
279 fd_table[clientConn->fd].useDefaultIo();
280
281 // TODO: Encapsulate this frequently repeated logic into a method.
282 const auto session = fd_table[serverConn->fd].ssl;
283 auto b = SSL_get_rbio(session.get());
284 auto srvBio = static_cast<Ssl::ServerBio*>(BIO_get_data(b));
285
2b6b1bcb 286 debugs(83, 5, "will tunnel instead of negotiating TLS");
1c2b4465 287 switchToTunnel(request.getRaw(), clientConn, serverConn, srvBio->rBufData());
2b6b1bcb
AR
288 answer().tunneled = true;
289 disconnect();
290 callBack();
1c2b4465
CT
291}
292
32f1ca3f
AJ
293void
294Ssl::PeekingPeerConnector::noteWantWrite()
295{
296 const int fd = serverConnection()->fd;
ad23e748
AJ
297 Security::SessionPointer session(fd_table[fd].ssl);
298 BIO *b = SSL_get_rbio(session.get());
093deea9 299 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
32f1ca3f
AJ
300
301 if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
bc8e1f18 302 debugs(81, 3, "hold write on SSL connection on FD " << fd);
32f1ca3f
AJ
303 checkForPeekAndSplice();
304 return;
305 }
306
a72b6e88 307 Security::PeerConnector::noteWantWrite();
32f1ca3f
AJ
308}
309
310void
83b053a0 311Ssl::PeekingPeerConnector::noteNegotiationError(const Security::ErrorDetailPointer &errorDetail)
32f1ca3f
AJ
312{
313 const int fd = serverConnection()->fd;
ad23e748
AJ
314 Security::SessionPointer session(fd_table[fd].ssl);
315 BIO *b = SSL_get_rbio(session.get());
093deea9 316 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
32f1ca3f 317
cd29a421
CT
318 if (srvBio->bumpMode() == Ssl::bumpPeek) {
319 auto bypassValidator = false;
320 if (srvBio->encryptedCertificates()) {
321 // it is pointless to peek at encrypted certificates
322 //
323 // we currently splice all sessions with encrypted certificates
324 // if (const auto spliceEncryptedCertificates = true) {
325 bypassValidator = true;
326 // } // else fall through to find a matching ssl_bump action (with limited info)
327 } else if (srvBio->resumingSession()) {
328 // In peek mode, the ClientHello message is forwarded to the server.
329 // If the server is resuming a previous (spliced) SSL session with
330 // the client, then probably we are here because our local SSL
331 // object does not know anything about the session being resumed.
332 //
333 // we currently splice all resumed sessions
334 // if (const auto spliceResumed = true) {
335 bypassValidator = true;
336 // } // else fall through to find a matching ssl_bump action (with limited info)
337 }
338
339 if (bypassValidator) {
340 bypassCertValidator();
341 checkForPeekAndSpliceMatched(Ssl::bumpSplice);
342 return;
343 }
32f1ca3f
AJ
344 }
345
346 // If we are in peek-and-splice mode and still we did not write to
347 // server yet, try to see if we should splice.
348 // In this case the connection can be saved.
349 // If the checklist decision is do not splice a new error will
350 // occur in the next SSL_connect call, and we will fail again.
351 // Abort on certificate validation errors to avoid splicing and
352 // thus hiding them.
353 // Abort if no certificate found probably because of malformed or
354 // unsupported server Hello message (TODO: make configurable).
d2f0c106
CT
355 // TODO: Add/use a positive "successfully validated server cert" signal
356 // instead of relying on the "![presumably_]validation_error && serverCert"
357 // signal combo.
ad23e748 358 if (!SSL_get_ex_data(session.get(), ssl_ex_index_ssl_error_detail) &&
32f1ca3f 359 (srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
ad23e748
AJ
360 Security::CertPointer serverCert(SSL_get_peer_certificate(session.get()));
361 if (serverCert) {
83b053a0 362 debugs(81, 3, "hold TLS write on FD " << fd << " despite " << errorDetail);
32f1ca3f
AJ
363 checkForPeekAndSplice();
364 return;
365 }
366 }
367
368 // else call parent noteNegotiationError to produce an error page
83b053a0 369 Security::PeerConnector::noteNegotiationError(errorDetail);
32f1ca3f
AJ
370}
371
372void
373Ssl::PeekingPeerConnector::handleServerCertificate()
374{
375 if (serverCertificateHandled)
376 return;
377
378 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
379 const int fd = serverConnection()->fd;
ad23e748
AJ
380 Security::SessionPointer session(fd_table[fd].ssl);
381 Security::CertPointer serverCert(SSL_get_peer_certificate(session.get()));
382 if (!serverCert)
32f1ca3f
AJ
383 return;
384
385 serverCertificateHandled = true;
386
387 // remember the server certificate for later use
388 if (Ssl::ServerBump *serverBump = csd->serverBump()) {
35b3559c 389 serverBump->serverCert = std::move(serverCert);
32f1ca3f
AJ
390 }
391 }
392}
393
394void
395Ssl::PeekingPeerConnector::serverCertificateVerified()
396{
397 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
398 Security::CertPointer serverCert;
399 if(Ssl::ServerBump *serverBump = csd->serverBump())
014a9017 400 serverCert.resetAndLock(serverBump->serverCert.get());
32f1ca3f
AJ
401 else {
402 const int fd = serverConnection()->fd;
ad23e748
AJ
403 Security::SessionPointer session(fd_table[fd].ssl);
404 serverCert.resetWithoutLocking(SSL_get_peer_certificate(session.get()));
32f1ca3f 405 }
ad23e748 406 if (serverCert) {
32f1ca3f
AJ
407 csd->resetSslCommonName(Ssl::CommonHostName(serverCert.get()));
408 debugs(83, 5, "HTTPS server CN: " << csd->sslCommonName() <<
409 " bumped: " << *serverConnection());
410 }
411 }
412}
413