]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/PeerConnector.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ssl / PeerConnector.cc
CommitLineData
a23223bf 1/*
ef57eb7b 2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
a23223bf 3 *
bbc27441
AJ
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.
a23223bf
CT
7 */
8
bbc27441
AJ
9/* DEBUG: section 17 Request Forwarding */
10
a23223bf
CT
11#include "squid.h"
12#include "acl/FilledChecklist.h"
13#include "base/AsyncCbdataCalls.h"
14#include "CachePeer.h"
15#include "client_side.h"
16#include "comm/Loops.h"
17#include "errorpage.h"
18#include "fde.h"
19#include "globals.h"
24438ec5 20#include "helper/ResultCode.h"
a23223bf
CT
21#include "HttpRequest.h"
22#include "neighbors.h"
2bcab852 23#include "security/NegotiationHistory.h"
7f4e9b73 24#include "SquidConfig.h"
31855516 25#include "ssl/bio.h"
a23223bf
CT
26#include "ssl/cert_validate_message.h"
27#include "ssl/Config.h"
28#include "ssl/ErrorDetail.h"
29#include "ssl/helper.h"
30#include "ssl/PeerConnector.h"
31#include "ssl/ServerBump.h"
32#include "ssl/support.h"
a23223bf
CT
33
34CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeerConnector);
1b091aec
CT
35CBDATA_NAMESPACED_CLASS_INIT(Ssl, BlindPeerConnector);
36CBDATA_NAMESPACED_CLASS_INIT(Ssl, PeekingPeerConnector);
a23223bf 37
37611b26 38Ssl::PeerConnector::PeerConnector(const Comm::ConnectionPointer &aServerConn, AsyncCall::Pointer &aCallback, const time_t timeout) :
f53969cc 39 AsyncJob("Ssl::PeerConnector"),
f53969cc 40 serverConn(aServerConn),
79fe57c2 41 certErrors(NULL),
f53969cc
SM
42 callback(aCallback),
43 negotiationTimeout(timeout),
44 startTime(squid_curtime),
1b091aec 45 useCertValidator_(false)
a23223bf
CT
46{
47 // if this throws, the caller's cb dialer is not our CbDialer
48 Must(dynamic_cast<CbDialer*>(callback->getDialer()));
49}
50
51Ssl::PeerConnector::~PeerConnector()
52{
1b091aec 53 cbdataReferenceDone(certErrors);
a23223bf
CT
54 debugs(83, 5, "Peer connector " << this << " gone");
55}
56
57bool Ssl::PeerConnector::doneAll() const
58{
59 return (!callback || callback->canceled()) && AsyncJob::doneAll();
60}
61
62/// Preps connection and SSL state. Calls negotiate().
63void
64Ssl::PeerConnector::start()
65{
66 AsyncJob::start();
67
1b091aec 68 if (prepareSocket() && (initializeSsl() != NULL))
a23223bf 69 negotiateSsl();
a23223bf
CT
70}
71
72void
73Ssl::PeerConnector::commCloseHandler(const CommCloseCbParams &params)
74{
75 debugs(83, 5, "FD " << params.fd << ", Ssl::PeerConnector=" << params.data);
76 connectionClosed("Ssl::PeerConnector::commCloseHandler");
77}
78
79void
80Ssl::PeerConnector::connectionClosed(const char *reason)
81{
82 mustStop(reason);
83 callback = NULL;
84}
85
86bool
87Ssl::PeerConnector::prepareSocket()
88{
89 const int fd = serverConnection()->fd;
90 if (!Comm::IsConnOpen(serverConn) || fd_table[serverConn->fd].closing()) {
91 connectionClosed("Ssl::PeerConnector::prepareSocket");
92 return false;
93 }
94
95 // watch for external connection closures
96 typedef CommCbMemFunT<Ssl::PeerConnector, CommCloseCbParams> Dialer;
97 closeHandler = JobCallback(9, 5, Dialer, this, Ssl::PeerConnector::commCloseHandler);
98 comm_add_close_handler(fd, closeHandler);
99 return true;
100}
101
1b091aec 102SSL *
a23223bf
CT
103Ssl::PeerConnector::initializeSsl()
104{
96993ee0 105 Security::ContextPtr sslContext(getSslContext());
a23223bf
CT
106 assert(sslContext);
107
1b091aec
CT
108 const int fd = serverConnection()->fd;
109
31855516
CT
110 SSL *ssl = Ssl::CreateClient(sslContext, fd, "server https start");
111 if (!ssl) {
a23223bf
CT
112 ErrorState *anErr = new ErrorState(ERR_SOCKET_FAILURE, Http::scInternalServerError, request.getRaw());
113 anErr->xerrno = errno;
114 debugs(83, DBG_IMPORTANT, "Error allocating SSL handle: " << ERR_error_string(ERR_get_error(), NULL));
76b64c80 115
1b091aec
CT
116 noteNegotiationDone(anErr);
117 bail(anErr);
118 return NULL;
a23223bf
CT
119 }
120
121 // If CertValidation Helper used do not lookup checklist for errors,
122 // but keep a list of errors to send it to CertValidator
123 if (!Ssl::TheConfig.ssl_crt_validator) {
124 // Create the ACL check list now, while we have access to more info.
125 // The list is used in ssl_verify_cb() and is freed in ssl_free().
126 if (acl_access *acl = ::Config.ssl_client.cert_error) {
127 ACLFilledChecklist *check = new ACLFilledChecklist(acl, request.getRaw(), dash_str);
128 // check->fd(fd); XXX: need client FD here
129 SSL_set_ex_data(ssl, ssl_ex_index_cert_error_check, check);
130 }
131 }
1b091aec 132 return ssl;
a23223bf
CT
133}
134
8aec3e1b
CT
135void
136Ssl::PeerConnector::setReadTimeout()
137{
138 int timeToRead;
139 if (negotiationTimeout) {
140 const int timeUsed = squid_curtime - startTime;
141 const int timeLeft = max(0, static_cast<int>(negotiationTimeout - timeUsed));
142 timeToRead = min(static_cast<int>(::Config.Timeout.read), timeLeft);
143 } else
144 timeToRead = ::Config.Timeout.read;
145 AsyncCall::Pointer nil;
146 commSetConnTimeout(serverConnection(), timeToRead, nil);
147}
148
a23223bf
CT
149void
150Ssl::PeerConnector::negotiateSsl()
151{
152 if (!Comm::IsConnOpen(serverConnection()) || fd_table[serverConnection()->fd].closing())
153 return;
154
155 const int fd = serverConnection()->fd;
156 SSL *ssl = fd_table[fd].ssl;
157 const int result = SSL_connect(ssl);
158 if (result <= 0) {
159 handleNegotiateError(result);
160 return; // we might be gone by now
161 }
162
c91d4d4e
CT
163 if (!sslFinalized())
164 return;
165
166 callBack();
167}
168
169bool
170Ssl::PeerConnector::sslFinalized()
171{
1b091aec
CT
172 if (Ssl::TheConfig.ssl_crt_validator && useCertValidator_) {
173 const int fd = serverConnection()->fd;
174 SSL *ssl = fd_table[fd].ssl;
a23223bf 175
a23223bf
CT
176 Ssl::CertValidationRequest validationRequest;
177 // WARNING: Currently we do not use any locking for any of the
178 // members of the Ssl::CertValidationRequest class. In this code the
179 // Ssl::CertValidationRequest object used only to pass data to
180 // Ssl::CertValidationHelper::submit method.
181 validationRequest.ssl = ssl;
5c51bffb 182 validationRequest.domainName = request->url.host();
a23223bf
CT
183 if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
184 // validationRequest disappears on return so no need to cbdataReference
185 validationRequest.errors = errs;
186 else
187 validationRequest.errors = NULL;
188 try {
189 debugs(83, 5, "Sending SSL certificate for validation to ssl_crtvd.");
0e208dad
CT
190 AsyncCall::Pointer call = asyncCall(83,5, "Ssl::PeerConnector::sslCrtvdHandleReply", Ssl::CertValidationHelper::CbDialer(this, &Ssl::PeerConnector::sslCrtvdHandleReply, nullptr));
191 Ssl::CertValidationHelper::GetInstance()->sslSubmit(validationRequest, call);
c91d4d4e 192 return false;
a23223bf
CT
193 } catch (const std::exception &e) {
194 debugs(83, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtvd " <<
195 "request for " << validationRequest.domainName <<
196 " certificate: " << e.what() << "; will now block to " <<
197 "validate that certificate.");
198 // fall through to do blocking in-process generation.
199 ErrorState *anErr = new ErrorState(ERR_GATEWAY_FAILURE, Http::scInternalServerError, request.getRaw());
1b091aec
CT
200
201 noteNegotiationDone(anErr);
a23223bf 202 bail(anErr);
a23223bf 203 serverConn->close();
c91d4d4e 204 return true;
a23223bf
CT
205 }
206 }
1b091aec
CT
207
208 noteNegotiationDone(NULL);
c91d4d4e 209 return true;
a23223bf
CT
210}
211
c91d4d4e 212void switchToTunnel(HttpRequest *request, Comm::ConnectionPointer & clientConn, Comm::ConnectionPointer &srvConn);
7f4e9b73 213
31855516 214void
1b091aec 215Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone(allow_t answer, void *data)
7f4e9b73 216{
1b091aec 217 Ssl::PeekingPeerConnector *peerConnect = (Ssl::PeekingPeerConnector *) data;
566f8310
AR
218 // Use job calls to add done() checks and other job logic/protections.
219 CallJobHere1(83, 7, CbcPointer<PeekingPeerConnector>(peerConnect), Ssl::PeekingPeerConnector, checkForPeekAndSpliceDone, answer);
220}
221
222void
223Ssl::PeekingPeerConnector::checkForPeekAndSpliceDone(allow_t answer)
224{
225 const Ssl::BumpMode finalAction = (answer.code == ACCESS_ALLOWED) ?
2d5fa7fa
SM
226 static_cast<Ssl::BumpMode>(answer.kind):
227 checkForPeekAndSpliceGuess();
566f8310 228 checkForPeekAndSpliceMatched(finalAction);
7f4e9b73
CT
229}
230
a9c2dd2f 231void
1b091aec 232Ssl::PeekingPeerConnector::checkForPeekAndSplice()
31855516 233{
5d65362c
CT
234 // Mark Step3 of bumping
235 if (request->clientConnectionManager.valid()) {
236 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
237 serverBump->step = Ssl::bumpStep3;
238 }
239 }
240
69f69080
CT
241 handleServerCertificate();
242
a9c2dd2f
CT
243 ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(
244 ::Config.accessList.ssl_bump,
245 request.getRaw(), NULL);
640fe8fb
CT
246 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpNone));
247 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpPeek));
248 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpStare));
249 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpClientFirst));
250 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpServerFirst));
251 SSL *ssl = fd_table[serverConn->fd].ssl;
252 BIO *b = SSL_get_rbio(ssl);
253 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
254 if (!srvBio->canSplice())
255 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpSplice));
256 if (!srvBio->canBump())
257 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpBump));
1b091aec 258 acl_checklist->nonBlockingCheck(Ssl::PeekingPeerConnector::cbCheckForPeekAndSpliceDone, this);
a9c2dd2f 259}
789dda8d 260
a9c2dd2f 261void
566f8310 262Ssl::PeekingPeerConnector::checkForPeekAndSpliceMatched(const Ssl::BumpMode action)
a9c2dd2f
CT
263{
264 SSL *ssl = fd_table[serverConn->fd].ssl;
31855516
CT
265 BIO *b = SSL_get_rbio(ssl);
266 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
8693472e 267 debugs(83,5, "Will check for peek and splice on FD " << serverConn->fd);
7f4e9b73 268
a9c2dd2f 269 Ssl::BumpMode finalAction = action;
640fe8fb 270 Must(finalAction == Ssl::bumpSplice || finalAction == Ssl::bumpBump || finalAction == Ssl::bumpTerminate);
a9c2dd2f 271 // Record final decision
68bd0182 272 if (request->clientConnectionManager.valid()) {
a9c2dd2f 273 request->clientConnectionManager->sslBumpMode = finalAction;
68bd0182
CT
274 request->clientConnectionManager->serverBump()->act.step3 = finalAction;
275 }
a9c2dd2f
CT
276
277 if (finalAction == Ssl::bumpTerminate) {
b54a7c5a
CT
278 serverConn->close();
279 clientConn->close();
a9c2dd2f 280 } else if (finalAction != Ssl::bumpSplice) {
31855516
CT
281 //Allow write, proceed with the connection
282 srvBio->holdWrite(false);
283 srvBio->recordInput(false);
8693472e 284 debugs(83,5, "Retry the fwdNegotiateSSL on FD " << serverConn->fd);
1b091aec 285 Ssl::PeerConnector::noteWantWrite();
93ead3fd 286 } else {
c91d4d4e 287 splice = true;
f53969cc 288 // Ssl Negotiation stops here. Last SSL checks for valid certificates
c91d4d4e 289 // and if done, switch to tunnel mode
1b091aec
CT
290 if (sslFinalized()) {
291 debugs(83,5, "Abort NegotiateSSL on FD " << serverConn->fd << " and splice the connection");
292 }
31855516
CT
293 }
294}
295
566f8310
AR
296Ssl::BumpMode
297Ssl::PeekingPeerConnector::checkForPeekAndSpliceGuess() const
298{
299 if (const ConnStateData *csd = request->clientConnectionManager.valid()) {
300 const Ssl::BumpMode currentMode = csd->sslBumpMode;
301 if (currentMode == Ssl::bumpStare) {
302 debugs(83,5, "default to bumping after staring");
303 return Ssl::bumpBump;
304 }
305 debugs(83,5, "default to splicing after " << currentMode);
306 } else {
307 debugs(83,3, "default to splicing due to missing info");
308 }
309
310 return Ssl::bumpSplice;
311}
312
a23223bf 313void
0e208dad 314Ssl::PeerConnector::sslCrtvdHandleReply(Ssl::CertValidationResponse::Pointer validationResponse)
a23223bf 315{
0e208dad 316 Must(validationResponse != NULL);
a23223bf 317
a23223bf
CT
318 Ssl::CertErrors *errs = NULL;
319 Ssl::ErrorDetail *errDetails = NULL;
320 bool validatorFailed = false;
321 if (!Comm::IsConnOpen(serverConnection())) {
322 return;
323 }
324
0e208dad 325 debugs(83,5, request->url.host() << " cert validation result: " << validationResponse->resultCode);
a23223bf 326
0e208dad
CT
327 if (validationResponse->resultCode == ::Helper::Error)
328 errs = sslCrtvdCheckForErrors(*validationResponse, errDetails);
329 else if (validationResponse->resultCode != ::Helper::Okay)
a23223bf
CT
330 validatorFailed = true;
331
332 if (!errDetails && !validatorFailed) {
1b091aec
CT
333 noteNegotiationDone(NULL);
334 callBack();
a23223bf
CT
335 return;
336 }
337
1b091aec
CT
338 if (errs) {
339 if (certErrors)
340 cbdataReferenceDone(certErrors);
341 certErrors = cbdataReference(errs);
342 }
343
a23223bf
CT
344 ErrorState *anErr = NULL;
345 if (validatorFailed) {
346 anErr = new ErrorState(ERR_GATEWAY_FAILURE, Http::scInternalServerError, request.getRaw());
347 } else {
a23223bf
CT
348 anErr = new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scServiceUnavailable, request.getRaw());
349 anErr->detail = errDetails;
350 /*anErr->xerrno= Should preserved*/
351 }
352
1b091aec 353 noteNegotiationDone(anErr);
a23223bf 354 bail(anErr);
a23223bf
CT
355 serverConn->close();
356 return;
357}
358
359/// Checks errors in the cert. validator response against sslproxy_cert_error.
360/// The first honored error, if any, is returned via errDetails parameter.
361/// The method returns all seen errors except SSL_ERROR_NONE as Ssl::CertErrors.
362Ssl::CertErrors *
363Ssl::PeerConnector::sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &resp, Ssl::ErrorDetail *& errDetails)
364{
365 Ssl::CertErrors *errs = NULL;
366
367 ACLFilledChecklist *check = NULL;
368 if (acl_access *acl = ::Config.ssl_client.cert_error)
369 check = new ACLFilledChecklist(acl, request.getRaw(), dash_str);
370
371 SSL *ssl = fd_table[serverConnection()->fd].ssl;
372 typedef Ssl::CertValidationResponse::RecvdErrors::const_iterator SVCRECI;
373 for (SVCRECI i = resp.errors.begin(); i != resp.errors.end(); ++i) {
374 debugs(83, 7, "Error item: " << i->error_no << " " << i->error_reason);
375
376 assert(i->error_no != SSL_ERROR_NONE);
377
378 if (!errDetails) {
379 bool allowed = false;
380 if (check) {
b4e6a8d4 381 check->sslErrors = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get(), i->error_depth));
a23223bf
CT
382 if (check->fastCheck() == ACCESS_ALLOWED)
383 allowed = true;
384 }
385 // else the Config.ssl_client.cert_error access list is not defined
386 // and the first error will cause the error page
387
388 if (allowed) {
389 debugs(83, 3, "bypassing SSL error " << i->error_no << " in " << "buffer");
390 } else {
391 debugs(83, 5, "confirming SSL error " << i->error_no);
392 X509 *brokenCert = i->cert.get();
f97700a0 393 Security::CertPointer peerCert(SSL_get_peer_certificate(ssl));
a23223bf
CT
394 const char *aReason = i->error_reason.empty() ? NULL : i->error_reason.c_str();
395 errDetails = new Ssl::ErrorDetail(i->error_no, peerCert.get(), brokenCert, aReason);
396 }
397 if (check) {
398 delete check->sslErrors;
399 check->sslErrors = NULL;
400 }
401 }
402
403 if (!errs)
b4e6a8d4 404 errs = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get(), i->error_depth));
a23223bf 405 else
b4e6a8d4 406 errs->push_back_unique(Ssl::CertError(i->error_no, i->cert.get(), i->error_depth));
a23223bf
CT
407 }
408 if (check)
409 delete check;
410
411 return errs;
412}
413
414/// A wrapper for Comm::SetSelect() notifications.
415void
416Ssl::PeerConnector::NegotiateSsl(int, void *data)
417{
418 PeerConnector *pc = static_cast<PeerConnector*>(data);
419 // Use job calls to add done() checks and other job logic/protections.
420 CallJobHere(83, 7, pc, Ssl::PeerConnector, negotiateSsl);
421}
422
423void
424Ssl::PeerConnector::handleNegotiateError(const int ret)
425{
426 const int fd = serverConnection()->fd;
427 unsigned long ssl_lib_error = SSL_ERROR_NONE;
428 SSL *ssl = fd_table[fd].ssl;
f5518dca 429 const int ssl_error = SSL_get_error(ssl, ret);
a23223bf 430
e2849af8 431 switch (ssl_error) {
e2849af8 432 case SSL_ERROR_WANT_READ:
1b091aec 433 noteWantRead();
e2849af8 434 return;
a23223bf 435
e2849af8 436 case SSL_ERROR_WANT_WRITE:
1b091aec 437 noteWantWrite();
e2849af8 438 return;
a23223bf 439
e2849af8
A
440 case SSL_ERROR_SSL:
441 case SSL_ERROR_SYSCALL:
442 ssl_lib_error = ERR_get_error();
1b091aec
CT
443 // proceed to the general error handling code
444 break;
445 default:
446 // no special error handling for all other errors
447 break;
448 }
449 noteSslNegotiationError(ret, ssl_error, ssl_lib_error);
450}
a23223bf 451
1b091aec
CT
452void
453Ssl::PeerConnector::noteWantRead()
454{
455 setReadTimeout();
456 const int fd = serverConnection()->fd;
457 Comm::SetSelect(fd, COMM_SELECT_READ, &NegotiateSsl, this, 0);
458}
7f4e9b73 459
1b091aec
CT
460void
461Ssl::PeerConnector::noteWantWrite()
462{
463 const int fd = serverConnection()->fd;
464 Comm::SetSelect(fd, COMM_SELECT_WRITE, &NegotiateSsl, this, 0);
465 return;
466}
a23223bf 467
1b091aec
CT
468void
469Ssl::PeerConnector::noteSslNegotiationError(const int ret, const int ssl_error, const int ssl_lib_error)
470{
471#ifdef EPROTO
472 int sysErrNo = EPROTO;
473#else
474 int sysErrNo = EACCES;
475#endif
a23223bf 476
1b091aec
CT
477 // store/report errno when ssl_error is SSL_ERROR_SYSCALL, ssl_lib_error is 0, and ret is -1
478 if (ssl_error == SSL_ERROR_SYSCALL && ret == -1 && ssl_lib_error == 0)
479 sysErrNo = errno;
a23223bf 480
1b091aec
CT
481 const int fd = serverConnection()->fd;
482 debugs(83, DBG_IMPORTANT, "Error negotiating SSL on FD " << fd <<
483 ": " << ERR_error_string(ssl_lib_error, NULL) << " (" <<
484 ssl_error << "/" << ret << "/" << errno << ")");
a23223bf 485
1b091aec
CT
486 ErrorState *anErr = NULL;
487 if (request != NULL)
488 anErr = ErrorState::NewForwarding(ERR_SECURE_CONNECT_FAIL, request.getRaw());
489 else
490 anErr = new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scServiceUnavailable, NULL);
a23223bf
CT
491 anErr->xerrno = sysErrNo;
492
1b091aec 493 SSL *ssl = fd_table[fd].ssl;
a23223bf
CT
494 Ssl::ErrorDetail *errFromFailure = (Ssl::ErrorDetail *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail);
495 if (errFromFailure != NULL) {
496 // The errFromFailure is attached to the ssl object
497 // and will be released when ssl object destroyed.
498 // Copy errFromFailure to a new Ssl::ErrorDetail object
499 anErr->detail = new Ssl::ErrorDetail(*errFromFailure);
500 } else {
501 // server_cert can be NULL here
502 X509 *server_cert = SSL_get_peer_certificate(ssl);
503 anErr->detail = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, server_cert, NULL);
504 X509_free(server_cert);
505 }
506
507 if (ssl_lib_error != SSL_ERROR_NONE)
508 anErr->detail->setLibError(ssl_lib_error);
509
1b091aec
CT
510 assert(certErrors == NULL);
511 // remember validation errors, if any
512 if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors*>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
513 certErrors = cbdataReference(errs);
a23223bf 514
1b091aec 515 noteNegotiationDone(anErr);
a23223bf
CT
516 bail(anErr);
517}
518
519void
520Ssl::PeerConnector::bail(ErrorState *error)
521{
522 Must(error); // or the recepient will not know there was a problem
a23223bf
CT
523 Must(callback != NULL);
524 CbDialer *dialer = dynamic_cast<CbDialer*>(callback->getDialer());
525 Must(dialer);
526 dialer->answer().error = error;
527
528 callBack();
529 // Our job is done. The callabck recepient will probably close the failed
530 // peer connection and try another peer or go direct (if possible). We
531 // can close the connection ourselves (our error notification would reach
532 // the recepient before the fd-closure notification), but we would rather
533 // minimize the number of fd-closure notifications and let the recepient
534 // manage the TCP state of the connection.
535}
536
537void
538Ssl::PeerConnector::callBack()
539{
540 AsyncCall::Pointer cb = callback;
541 // Do this now so that if we throw below, swanSong() assert that we _tried_
542 // to call back holds.
543 callback = NULL; // this should make done() true
544
545 // remove close handler
546 comm_remove_close_handler(serverConnection()->fd, closeHandler);
547
548 CbDialer *dialer = dynamic_cast<CbDialer*>(cb->getDialer());
549 Must(dialer);
550 dialer->answer().conn = serverConnection();
551 ScheduleCallHere(cb);
552}
553
a23223bf
CT
554void
555Ssl::PeerConnector::swanSong()
556{
557 // XXX: unregister fd-closure monitoring and CommSetSelect interest, if any
558 AsyncJob::swanSong();
566f8310
AR
559 if (callback != NULL) { // paranoid: we have left the caller waiting
560 debugs(83, DBG_IMPORTANT, "BUG: Unexpected state while connecting to a cache_peer or origin server");
561 ErrorState *anErr = new ErrorState(ERR_GATEWAY_FAILURE, Http::scInternalServerError, request.getRaw());
562 bail(anErr);
563 assert(!callback);
564 return;
565 }
a23223bf
CT
566}
567
568const char *
569Ssl::PeerConnector::status() const
570{
571 static MemBuf buf;
572 buf.reset();
573
574 // TODO: redesign AsyncJob::status() API to avoid this
575 // id and stop reason reporting duplication.
576 buf.append(" [", 2);
577 if (stopReason != NULL) {
07e6d76e
AJ
578 buf.append("Stopped, reason:", 16);
579 buf.appendf("%s",stopReason);
a23223bf
CT
580 }
581 if (serverConn != NULL)
07e6d76e
AJ
582 buf.appendf(" FD %d", serverConn->fd);
583 buf.appendf(" %s%u]", id.Prefix, id.value);
a23223bf
CT
584 buf.terminate();
585
586 return buf.content();
587}
588
96993ee0 589Security::ContextPtr
1b091aec
CT
590Ssl::BlindPeerConnector::getSslContext()
591{
592 if (const CachePeer *peer = serverConnection()->getPeer()) {
593 assert(peer->secure.encryptTransport);
96993ee0 594 Security::ContextPtr sslContext(peer->sslContext);
1b091aec
CT
595 return sslContext;
596 }
41e803be 597 return ::Config.ssl_client.sslContext;
1b091aec
CT
598}
599
600SSL *
601Ssl::BlindPeerConnector::initializeSsl()
602{
603 SSL *ssl = Ssl::PeerConnector::initializeSsl();
604 if (!ssl)
605 return NULL;
606
41e803be
CT
607 if (const CachePeer *peer = serverConnection()->getPeer()) {
608 assert(peer);
1b091aec 609
41e803be
CT
610 // NP: domain may be a raw-IP but it is now always set
611 assert(!peer->secure.sslDomain.isEmpty());
1b091aec 612
41e803be
CT
613 // const loss is okay here, ssl_ex_index_server is only read and not assigned a destructor
614 SBuf *host = new SBuf(peer->secure.sslDomain);
615 SSL_set_ex_data(ssl, ssl_ex_index_server, host);
1b091aec 616
41e803be
CT
617 if (peer->sslSession)
618 SSL_set_session(ssl, peer->sslSession);
619 } else {
620 SBuf *hostName = new SBuf(request->url.host());
621 SSL_set_ex_data(ssl, ssl_ex_index_server, (void*)hostName);
622 }
1b091aec
CT
623
624 return ssl;
625}
626
627void
628Ssl::BlindPeerConnector::noteNegotiationDone(ErrorState *error)
629{
630 if (error) {
631 // XXX: forward.cc calls peerConnectSucceeded() after an OK TCP connect but
632 // we call peerConnectFailed() if SSL failed afterwards. Is that OK?
633 // It is not clear whether we should call peerConnectSucceeded/Failed()
634 // based on TCP results, SSL results, or both. And the code is probably not
635 // consistent in this aspect across tunnelling and forwarding modules.
636 if (CachePeer *p = serverConnection()->getPeer())
637 peerConnectFailed(p);
638 return;
639 }
640
641 const int fd = serverConnection()->fd;
642 SSL *ssl = fd_table[fd].ssl;
643 if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
644 if (serverConnection()->getPeer()->sslSession)
645 SSL_SESSION_free(serverConnection()->getPeer()->sslSession);
646
647 serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl);
648 }
649}
650
96993ee0 651Security::ContextPtr
1b091aec
CT
652Ssl::PeekingPeerConnector::getSslContext()
653{
654 // XXX: locate a per-server context in Security:: instead
655 return ::Config.ssl_client.sslContext;
656}
657
658SSL *
659Ssl::PeekingPeerConnector::initializeSsl()
660{
661 SSL *ssl = Ssl::PeerConnector::initializeSsl();
662 if (!ssl)
663 return NULL;
664
665 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
666
667 // client connection is required in the case we need to splice
668 // or terminate client and server connections
669 assert(clientConn != NULL);
670 SBuf *hostName = NULL;
671 Ssl::ClientBio *cltBio = NULL;
672
673 //Enable Status_request tls extension, required to bump some clients
674 SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
675
676 // In server-first bumping mode, clientSsl is NULL.
677 if (SSL *clientSsl = fd_table[clientConn->fd].ssl) {
678 BIO *b = SSL_get_rbio(clientSsl);
679 cltBio = static_cast<Ssl::ClientBio *>(b->ptr);
2bcab852 680 const Ssl::Bio::sslFeatures &features = cltBio->receivedHelloFeatures();
1b091aec
CT
681 if (!features.serverName.isEmpty())
682 hostName = new SBuf(features.serverName);
683 }
684
685 if (!hostName) {
686 // While we are peeking at the certificate, we may not know the server
687 // name that the client will request (after interception or CONNECT)
688 // unless it was the CONNECT request with a user-typed address.
689 const bool isConnectRequest = !csd->port->flags.isIntercepted();
690 if (!request->flags.sslPeek || isConnectRequest)
5c51bffb 691 hostName = new SBuf(request->url.host());
1b091aec
CT
692 }
693
694 if (hostName)
695 SSL_set_ex_data(ssl, ssl_ex_index_server, (void*)hostName);
696
697 Must(!csd->serverBump() || csd->serverBump()->step <= Ssl::bumpStep2);
698 if (csd->sslBumpMode == Ssl::bumpPeek || csd->sslBumpMode == Ssl::bumpStare) {
699 assert(cltBio);
2bcab852 700 const Ssl::Bio::sslFeatures &features = cltBio->receivedHelloFeatures();
1b091aec
CT
701 if (features.sslVersion != -1) {
702 features.applyToSSL(ssl, csd->sslBumpMode);
703 // Should we allow it for all protocols?
704 if (features.sslVersion >= 3) {
705 BIO *b = SSL_get_rbio(ssl);
706 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
707 // Inherite client features, like SSL version, SNI and other
708 srvBio->setClientFeatures(features);
709 srvBio->recordInput(true);
710 srvBio->mode(csd->sslBumpMode);
711 }
712 }
713 } else {
714 // Set client SSL options
715 SSL_set_options(ssl, ::Security::ProxyOutgoingConfig.parsedOptions);
716
717 // Use SNI TLS extension only when we connect directly
718 // to the origin server and we know the server host name.
c52a4693
AW
719 const char *sniServer = NULL;
720 const bool redirected = request->flags.redirected && ::Config.onoff.redir_rewrites_host;
721 if (!hostName || redirected)
722 sniServer = !request->url.hostIsNumeric() ? request->url.host() : NULL;
723 else
724 sniServer = hostName->c_str();
725
1b091aec
CT
726 if (sniServer)
727 Ssl::setClientSNI(ssl, sniServer);
728 }
729
730 // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
731 X509 *peeked_cert;
732 if (csd->serverBump() &&
733 (peeked_cert = csd->serverBump()->serverCert.get())) {
734 CRYPTO_add(&(peeked_cert->references),1,CRYPTO_LOCK_X509);
735 SSL_set_ex_data(ssl, ssl_ex_index_ssl_peeked_cert, peeked_cert);
736 }
737 }
738
739 return ssl;
740}
741
742void
743Ssl::PeekingPeerConnector::noteNegotiationDone(ErrorState *error)
744{
745 SSL *ssl = fd_table[serverConnection()->fd].ssl;
746
747 // Check the list error with
748 if (!request->clientConnectionManager.valid() || ! ssl)
749 return;
750
751 // remember the server certificate from the ErrorDetail object
752 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
753 // remember validation errors, if any
754 if (certErrors) {
755 if (serverBump->sslErrors)
756 cbdataReferenceDone(serverBump->sslErrors);
757 serverBump->sslErrors = cbdataReference(certErrors);
758 }
759
760 if (!serverBump->serverCert.get()) {
761 // remember the server certificate from the ErrorDetail object
762 if (error && error->detail && error->detail->peerCert())
763 serverBump->serverCert.resetAndLock(error->detail->peerCert());
764 else {
765 handleServerCertificate();
766 }
767 }
768
769 if (error) {
770 // For intercepted connections, set the host name to the server
771 // certificate CN. Otherwise, we just hope that CONNECT is using
772 // a user-entered address (a host name or a user-entered IP).
773 const bool isConnectRequest = !request->clientConnectionManager->port->flags.isIntercepted();
774 if (request->flags.sslPeek && !isConnectRequest) {
775 if (X509 *srvX509 = serverBump->serverCert.get()) {
776 if (const char *name = Ssl::CommonHostName(srvX509)) {
851feda6 777 request->url.host(name);
1b091aec
CT
778 debugs(83, 3, "reset request host: " << name);
779 }
780 }
781 }
782 }
783 }
784
2bcab852
CT
785 // retrieve TLS server information if any
786 serverConnection()->tlsNegotiations()->fillWith(ssl);
ce74a2eb
CT
787 if (!error) {
788 serverCertificateVerified();
2bcab852
CT
789 if (splice) {
790 //retrieved received TLS client informations
791 SSL *clientSsl = fd_table[clientConn->fd].ssl;
792 clientConn->tlsNegotiations()->fillWith(clientSsl);
ce74a2eb 793 switchToTunnel(request.getRaw(), clientConn, serverConn);
2bcab852 794 }
ce74a2eb 795 }
1b091aec
CT
796}
797
798void
799Ssl::PeekingPeerConnector::noteWantWrite()
800{
801 const int fd = serverConnection()->fd;
802 SSL *ssl = fd_table[fd].ssl;
803 BIO *b = SSL_get_rbio(ssl);
804 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
805
806 if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
807 debugs(81, DBG_IMPORTANT, "hold write on SSL connection on FD " << fd);
808 checkForPeekAndSplice();
809 return;
810 }
811
812 Ssl::PeerConnector::noteWantWrite();
813}
814
815void
816Ssl::PeekingPeerConnector::noteSslNegotiationError(const int result, const int ssl_error, const int ssl_lib_error)
817{
818 const int fd = serverConnection()->fd;
819 SSL *ssl = fd_table[fd].ssl;
820 BIO *b = SSL_get_rbio(ssl);
821 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
822
823 // In Peek mode, the ClientHello message sent to the server. If the
824 // server resuming a previous (spliced) SSL session with the client,
825 // then probably we are here because local SSL object does not know
826 // anything about the session being resumed.
827 //
828 if (srvBio->bumpMode() == Ssl::bumpPeek && (resumingSession = srvBio->resumingSession())) {
829 // we currently splice all resumed sessions unconditionally
830 if (const bool spliceResumed = true) {
831 bypassCertValidator();
566f8310 832 checkForPeekAndSpliceMatched(Ssl::bumpSplice);
1b091aec
CT
833 return;
834 } // else fall through to find a matching ssl_bump action (with limited info)
835 }
836
837 // If we are in peek-and-splice mode and still we did not write to
838 // server yet, try to see if we should splice.
839 // In this case the connection can be saved.
840 // If the checklist decision is do not splice a new error will
841 // occur in the next SSL_connect call, and we will fail again.
842 // Abort on certificate validation errors to avoid splicing and
843 // thus hiding them.
844 // Abort if no certificate found probably because of malformed or
845 // unsupported server Hello message (TODO: make configurable).
846 if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) &&
847 (srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
f97700a0 848 Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
1b091aec
CT
849 if (serverCert.get()) {
850 debugs(81, 3, "Error (" << ERR_error_string(ssl_lib_error, NULL) << ") but, hold write on SSL connection on FD " << fd);
851 checkForPeekAndSplice();
852 return;
853 }
854 }
855
856 // else call parent noteNegotiationError to produce an error page
857 Ssl::PeerConnector::noteSslNegotiationError(result, ssl_error, ssl_lib_error);
858}
859
860void
861Ssl::PeekingPeerConnector::handleServerCertificate()
862{
863 if (serverCertificateHandled)
864 return;
865
866 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
867 const int fd = serverConnection()->fd;
868 SSL *ssl = fd_table[fd].ssl;
f97700a0 869 Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
1b091aec
CT
870 if (!serverCert.get())
871 return;
872
873 serverCertificateHandled = true;
874
1b091aec
CT
875 // remember the server certificate for later use
876 if (Ssl::ServerBump *serverBump = csd->serverBump()) {
877 serverBump->serverCert.reset(serverCert.release());
878 }
879 }
880}
7fe542fe 881
ce74a2eb
CT
882void
883Ssl::PeekingPeerConnector::serverCertificateVerified()
884{
885 if (ConnStateData *csd = request->clientConnectionManager.valid()) {
f97700a0 886 Security::CertPointer serverCert;
ce74a2eb
CT
887 if(Ssl::ServerBump *serverBump = csd->serverBump())
888 serverCert.resetAndLock(serverBump->serverCert.get());
889 else {
890 const int fd = serverConnection()->fd;
891 SSL *ssl = fd_table[fd].ssl;
892 serverCert.reset(SSL_get_peer_certificate(ssl));
893 }
894 if (serverCert.get()) {
895 csd->resetSslCommonName(Ssl::CommonHostName(serverCert.get()));
896 debugs(83, 5, "HTTPS server CN: " << csd->sslCommonName() <<
897 " bumped: " << *serverConnection());
898 }
899 }
900}
901