PeerConnector.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 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 /* DEBUG: section 83 TLS Server/Peer negotiation */
10 
11 #include "squid.h"
12 #include "acl/FilledChecklist.h"
13 #include "comm/Loops.h"
14 #include "Downloader.h"
15 #include "errorpage.h"
16 #include "fde.h"
17 #include "http/Stream.h"
18 #include "HttpRequest.h"
20 #include "security/PeerConnector.h"
21 #include "SquidConfig.h"
22 #if USE_OPENSSL
23 #include "ssl/bio.h"
25 #include "ssl/Config.h"
26 #include "ssl/helper.h"
27 #endif
28 
29 CBDATA_NAMESPACED_CLASS_INIT(Security, PeerConnector);
30 
31 Security::PeerConnector::PeerConnector(const Comm::ConnectionPointer &aServerConn, AsyncCall::Pointer &aCallback, const AccessLogEntryPointer &alp, const time_t timeout) :
32  AsyncJob("Security::PeerConnector"),
33  serverConn(aServerConn),
34  al(alp),
35  callback(aCallback),
36  negotiationTimeout(timeout),
37  startTime(squid_curtime),
38  useCertValidator_(true),
39  certsDownloads(0)
40 {
41  debugs(83, 5, "Security::PeerConnector constructed, this=" << (void*)this);
42  // if this throws, the caller's cb dialer is not our CbDialer
43  Must(dynamic_cast<CbDialer*>(callback->getDialer()));
44 }
45 
47 {
48  debugs(83, 5, "Security::PeerConnector destructed, this=" << (void*)this);
49 }
50 
52 {
53  return (!callback || callback->canceled()) && AsyncJob::doneAll();
54 }
55 
57 void
59 {
61  debugs(83, 5, "this=" << (void*)this);
62 
64  if (prepareSocket() && initialize(tmp))
65  negotiate();
66  else
67  mustStop("Security::PeerConnector TLS socket initialize failed");
68 }
69 
70 void
72 {
73  debugs(83, 5, "FD " << params.fd << ", Security::PeerConnector=" << params.data);
74  connectionClosed("Security::PeerConnector::commCloseHandler");
75 }
76 
77 void
79 {
80  debugs(83, 5, reason << " socket closed/closing. this=" << (void*)this);
81  mustStop(reason);
82  callback = NULL;
83 }
84 
85 bool
87 {
88  debugs(83, 5, serverConnection() << ", this=" << (void*)this);
89  if (!Comm::IsConnOpen(serverConnection()) || fd_table[serverConnection()->fd].closing()) {
90  connectionClosed("Security::PeerConnector::prepareSocket");
91  return false;
92  }
93 
94  debugs(83, 5, serverConnection());
95 
96  // watch for external connection closures
98  closeHandler = JobCallback(9, 5, Dialer, this, Security::PeerConnector::commCloseHandler);
99  comm_add_close_handler(serverConnection()->fd, closeHandler);
100  return true;
101 }
102 
103 bool
105 {
106  Security::ContextPointer ctx(getTlsContext());
107  debugs(83, 5, serverConnection() << ", ctx=" << (void*)ctx.get());
108 
109  if (!ctx || !Security::CreateClientSession(ctx, serverConnection(), "server https start")) {
110  const auto xerrno = errno;
111  if (!ctx) {
112  debugs(83, DBG_IMPORTANT, "Error initializing TLS connection: No security context.");
113  } // else CreateClientSession() did the appropriate debugs() already
115  anErr->xerrno = xerrno;
116  noteNegotiationDone(anErr);
117  bail(anErr);
118  return false;
119  }
120 
121  // A TLS/SSL session has now been created for the connection and stored in fd_table
122  serverSession = fd_table[serverConnection()->fd].ssl;
123  debugs(83, 5, serverConnection() << ", session=" << (void*)serverSession.get());
124 
125 #if USE_OPENSSL
126  // If CertValidation Helper used do not lookup checklist for errors,
127  // but keep a list of errors to send it to CertValidator
128  if (!Ssl::TheConfig.ssl_crt_validator) {
129  // Create the ACL check list now, while we have access to more info.
130  // The list is used in ssl_verify_cb() and is freed in ssl_free().
131  if (acl_access *acl = ::Config.ssl_client.cert_error) {
132  ACLFilledChecklist *check = new ACLFilledChecklist(acl, request.getRaw(), dash_str);
133  check->al = al;
134  check->syncAle(request.getRaw(), nullptr);
135  // check->fd(fd); XXX: need client FD here
136  SSL_set_ex_data(serverSession.get(), ssl_ex_index_cert_error_check, check);
137  }
138  }
139 #endif
140 
141  return true;
142 }
143 
144 void
146 {
147  int timeToRead;
148  if (negotiationTimeout) {
149  const int timeUsed = squid_curtime - startTime;
150  const int timeLeft = max(0, static_cast<int>(negotiationTimeout - timeUsed));
151  timeToRead = min(static_cast<int>(::Config.Timeout.read), timeLeft);
152  } else
153  timeToRead = ::Config.Timeout.read;
154  AsyncCall::Pointer nil;
155  commSetConnTimeout(serverConnection(), timeToRead, nil);
156 }
157 
158 void
160 {
161  const int fd = serverConnection()->fd;
162  Security::SessionPointer session(fd_table[fd].ssl);
163 
164  // retrieve TLS server negotiated information if any
165  serverConnection()->tlsNegotiations()->retrieveNegotiatedInfo(session);
166 
167 #if USE_OPENSSL
168  // retrieve TLS parsed extra info
169  BIO *b = SSL_get_rbio(session.get());
170  Ssl::ServerBio *bio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
171  if (const Security::TlsDetails::Pointer &details = bio->receivedHelloDetails())
172  serverConnection()->tlsNegotiations()->retrieveParsedInfo(details);
173 #endif
174 }
175 
176 void
178 {
179  if (!Comm::IsConnOpen(serverConnection()))
180  return;
181 
182  const int fd = serverConnection()->fd;
183  if (fd_table[fd].closing())
184  return;
185 
186 #if USE_OPENSSL
187  auto session = fd_table[fd].ssl.get();
188  debugs(83, 5, "SSL_connect session=" << (void*)session);
189  const int result = SSL_connect(session);
190  if (result <= 0) {
191 #elif USE_GNUTLS
192  auto session = fd_table[fd].ssl.get();
193  const int result = gnutls_handshake(session);
194  debugs(83, 5, "gnutls_handshake session=" << (void*)session << ", result=" << result);
195 
196  if (result == GNUTLS_E_SUCCESS) {
197  char *desc = gnutls_session_get_desc(session);
198  debugs(83, 2, serverConnection() << " TLS Session info: " << desc);
199  gnutls_free(desc);
200  }
201 
202  if (result != GNUTLS_E_SUCCESS) {
203  // debug the TLS session state so far
204  auto descIn = gnutls_handshake_get_last_in(session);
205  debugs(83, 2, "handshake IN: " << gnutls_handshake_description_get_name(descIn));
206  auto descOut = gnutls_handshake_get_last_out(session);
207  debugs(83, 2, "handshake OUT: " << gnutls_handshake_description_get_name(descOut));
208 #else
209  if (const int result = -1) {
210 #endif
211  handleNegotiateError(result);
212  return; // we might be gone by now
213  }
214 
215  recordNegotiationDetails();
216 
217  if (!sslFinalized())
218  return;
219 
220  callBack();
221 }
222 
223 bool
225 {
226 #if USE_OPENSSL
227  if (Ssl::TheConfig.ssl_crt_validator && useCertValidator_) {
228  const int fd = serverConnection()->fd;
229  Security::SessionPointer session(fd_table[fd].ssl);
230 
231  Ssl::CertValidationRequest validationRequest;
232  // WARNING: Currently we do not use any locking for 'errors' member
233  // of the Ssl::CertValidationRequest class. In this code the
234  // Ssl::CertValidationRequest object used only to pass data to
235  // Ssl::CertValidationHelper::submit method.
236  validationRequest.ssl = session;
237  if (SBuf *dName = (SBuf *)SSL_get_ex_data(session.get(), ssl_ex_index_server))
238  validationRequest.domainName = dName->c_str();
239  if (Security::CertErrors *errs = static_cast<Security::CertErrors *>(SSL_get_ex_data(session.get(), ssl_ex_index_ssl_errors)))
240  // validationRequest disappears on return so no need to cbdataReference
241  validationRequest.errors = errs;
242  try {
243  debugs(83, 5, "Sending SSL certificate for validation to ssl_crtvd.");
244  AsyncCall::Pointer call = asyncCall(83,5, "Security::PeerConnector::sslCrtvdHandleReply", Ssl::CertValidationHelper::CbDialer(this, &Security::PeerConnector::sslCrtvdHandleReply, nullptr));
245  Ssl::CertValidationHelper::Submit(validationRequest, call);
246  return false;
247  } catch (const std::exception &e) {
248  debugs(83, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtvd " <<
249  "request for " << validationRequest.domainName <<
250  " certificate: " << e.what() << "; will now block to " <<
251  "validate that certificate.");
252  // fall through to do blocking in-process generation.
254 
255  noteNegotiationDone(anErr);
256  bail(anErr);
257  serverConn->close();
258  return true;
259  }
260  }
261 #endif
262 
263  noteNegotiationDone(NULL);
264  return true;
265 }
266 
267 #if USE_OPENSSL
268 void
270 {
271  Must(validationResponse != NULL);
272 
273  Ssl::ErrorDetail *errDetails = NULL;
274  bool validatorFailed = false;
275  if (!Comm::IsConnOpen(serverConnection())) {
276  return;
277  }
278 
279  if (Debug::Enabled(83, 5)) {
280  Security::SessionPointer ssl(fd_table[serverConnection()->fd].ssl);
281  SBuf *server = static_cast<SBuf *>(SSL_get_ex_data(ssl.get(), ssl_ex_index_server));
282  debugs(83,5, RawPointer("host", server) << " cert validation result: " << validationResponse->resultCode);
283  }
284 
285  if (validationResponse->resultCode == ::Helper::Error) {
286  if (Security::CertErrors *errs = sslCrtvdCheckForErrors(*validationResponse, errDetails)) {
287  Security::SessionPointer session(fd_table[serverConnection()->fd].ssl);
288  Security::CertErrors *oldErrs = static_cast<Security::CertErrors*>(SSL_get_ex_data(session.get(), ssl_ex_index_ssl_errors));
289  SSL_set_ex_data(session.get(), ssl_ex_index_ssl_errors, (void *)errs);
290  delete oldErrs;
291  }
292  } else if (validationResponse->resultCode != ::Helper::Okay)
293  validatorFailed = true;
294 
295  if (!errDetails && !validatorFailed) {
296  noteNegotiationDone(NULL);
297  callBack();
298  return;
299  }
300 
301  ErrorState *anErr = NULL;
302  if (validatorFailed) {
304  } else {
306  anErr->detail = errDetails;
307  /*anErr->xerrno= Should preserved*/
308  }
309 
310  noteNegotiationDone(anErr);
311  bail(anErr);
312  serverConn->close();
313  return;
314 }
315 #endif
316 
317 #if USE_OPENSSL
323 {
324  ACLFilledChecklist *check = NULL;
325  if (acl_access *acl = ::Config.ssl_client.cert_error) {
326  check = new ACLFilledChecklist(acl, request.getRaw(), dash_str);
327  check->al = al;
328  check->syncAle(request.getRaw(), nullptr);
329  }
330 
331  Security::CertErrors *errs = nullptr;
332  Security::SessionPointer session(fd_table[serverConnection()->fd].ssl);
333  typedef Ssl::CertValidationResponse::RecvdErrors::const_iterator SVCRECI;
334  for (SVCRECI i = resp.errors.begin(); i != resp.errors.end(); ++i) {
335  debugs(83, 7, "Error item: " << i->error_no << " " << i->error_reason);
336 
337  assert(i->error_no != SSL_ERROR_NONE);
338 
339  if (!errDetails) {
340  bool allowed = false;
341  if (check) {
342  check->sslErrors = new Security::CertErrors(Security::CertError(i->error_no, i->cert, i->error_depth));
343  if (check->fastCheck().allowed())
344  allowed = true;
345  }
346  // else the Config.ssl_client.cert_error access list is not defined
347  // and the first error will cause the error page
348 
349  if (allowed) {
350  debugs(83, 3, "bypassing SSL error " << i->error_no << " in " << "buffer");
351  } else {
352  debugs(83, 5, "confirming SSL error " << i->error_no);
353  X509 *brokenCert = i->cert.get();
354  Security::CertPointer peerCert(SSL_get_peer_certificate(session.get()));
355  const char *aReason = i->error_reason.empty() ? NULL : i->error_reason.c_str();
356  errDetails = new Ssl::ErrorDetail(i->error_no, peerCert.get(), brokenCert, aReason);
357  }
358  if (check) {
359  delete check->sslErrors;
360  check->sslErrors = NULL;
361  }
362  }
363 
364  if (!errs)
365  errs = new Security::CertErrors(Security::CertError(i->error_no, i->cert, i->error_depth));
366  else
367  errs->push_back_unique(Security::CertError(i->error_no, i->cert, i->error_depth));
368  }
369  if (check)
370  delete check;
371 
372  return errs;
373 }
374 #endif
375 
377 void
379 {
380  const auto pc = static_cast<PeerConnector::Pointer*>(data);
381  if (pc->valid())
382  (*pc)->negotiateSsl();
383  delete pc;
384 }
385 
387 void
389 {
390  // Use job calls to add done() checks and other job logic/protections.
391  CallJobHere(83, 7, this, Security::PeerConnector, negotiate);
392 }
393 
394 void
396 {
397  const int fd = serverConnection()->fd;
398  const Security::SessionPointer session(fd_table[fd].ssl);
399  unsigned long ssl_lib_error = ret;
400 
401 #if USE_OPENSSL
402  const int ssl_error = SSL_get_error(session.get(), ret);
403 
404  switch (ssl_error) {
405  case SSL_ERROR_WANT_READ:
406  noteWantRead();
407  return;
408 
409  case SSL_ERROR_WANT_WRITE:
410  noteWantWrite();
411  return;
412 
413  case SSL_ERROR_SSL:
414  case SSL_ERROR_SYSCALL:
415  ssl_lib_error = ERR_get_error();
416  // proceed to the general error handling code
417  break;
418  default:
419  // no special error handling for all other errors
420  ssl_lib_error = SSL_ERROR_NONE;
421  break;
422  }
423 
424 #elif USE_GNUTLS
425  const int ssl_error = ret;
426 
427  switch (ret) {
428  case GNUTLS_E_WARNING_ALERT_RECEIVED: {
429  auto alert = gnutls_alert_get(session.get());
430  debugs(83, DBG_IMPORTANT, "TLS ALERT: " << gnutls_alert_get_name(alert));
431  }
432  // drop through to next case
433 
434  case GNUTLS_E_AGAIN:
435  case GNUTLS_E_INTERRUPTED:
436  if (gnutls_record_get_direction(session.get()) == 0)
437  noteWantRead();
438  else
439  noteWantWrite();
440  return;
441 
442  default:
443  // no special error handling for all other errors
444  break;
445  }
446 
447 #else
448  // this avoids unused variable compiler warnings.
449  Must(!session);
450  const int ssl_error = ret;
451 #endif
452 
453  // Log connection details, if any
454  recordNegotiationDetails();
455  noteNegotiationError(ret, ssl_error, ssl_lib_error);
456 }
457 
458 void
460 {
461  const int fd = serverConnection()->fd;
462  debugs(83, 5, serverConnection());
463 #if USE_OPENSSL
464  Security::SessionPointer session(fd_table[fd].ssl);
465  BIO *b = SSL_get_rbio(session.get());
466  Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
467  if (srvBio->holdRead()) {
468  if (srvBio->gotHello()) {
469  if (checkForMissingCertificates())
470  return; // Wait to download certificates before proceed.
471 
472  srvBio->holdRead(false);
473  // schedule a negotiateSSl to allow openSSL parse received data
474  negotiateSsl();
475  return;
476  } else if (srvBio->gotHelloFailed()) {
477  srvBio->holdRead(false);
478  debugs(83, DBG_IMPORTANT, "Error parsing SSL Server Hello Message on FD " << fd);
479  // schedule a negotiateSSl to allow openSSL parse received data
480  negotiateSsl();
481  return;
482  }
483  }
484 #endif
485  setReadTimeout();
486  Comm::SetSelect(fd, COMM_SELECT_READ, &NegotiateSsl, new Pointer(this), 0);
487 }
488 
489 void
491 {
492  const int fd = serverConnection()->fd;
493  debugs(83, 5, serverConnection());
494  Comm::SetSelect(fd, COMM_SELECT_WRITE, &NegotiateSsl, new Pointer(this), 0);
495  return;
496 }
497 
498 void
499 Security::PeerConnector::noteNegotiationError(const int ret, const int ssl_error, const int ssl_lib_error)
500 {
501 #if defined(EPROTO)
502  int sysErrNo = EPROTO;
503 #else
504  int sysErrNo = EACCES;
505 #endif
506 
507 #if USE_OPENSSL
508  // store/report errno when ssl_error is SSL_ERROR_SYSCALL, ssl_lib_error is 0, and ret is -1
509  if (ssl_error == SSL_ERROR_SYSCALL && ret == -1 && ssl_lib_error == 0)
510  sysErrNo = errno;
511 #endif
512  int xerr = errno;
513 
514  const int fd = serverConnection()->fd;
515  debugs(83, DBG_IMPORTANT, "ERROR: negotiating TLS on FD " << fd <<
516  ": " << Security::ErrorString(ssl_lib_error) << " (" <<
517  ssl_error << "/" << ret << "/" << xerr << ")");
518 
520  anErr->xerrno = sysErrNo;
521 
522 #if USE_OPENSSL
523  Security::SessionPointer session(fd_table[fd].ssl);
524  Ssl::ErrorDetail *errFromFailure = static_cast<Ssl::ErrorDetail *>(SSL_get_ex_data(session.get(), ssl_ex_index_ssl_error_detail));
525  if (errFromFailure != NULL) {
526  // The errFromFailure is attached to the ssl object
527  // and will be released when ssl object destroyed.
528  // Copy errFromFailure to a new Ssl::ErrorDetail object
529  anErr->detail = new Ssl::ErrorDetail(*errFromFailure);
530  } else {
531  // server_cert can be NULL here
532  X509 *server_cert = SSL_get_peer_certificate(session.get());
533  anErr->detail = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, server_cert, NULL);
534  X509_free(server_cert);
535  }
536 
537  if (ssl_lib_error != SSL_ERROR_NONE)
538  anErr->detail->setLibError(ssl_lib_error);
539 #endif
540 
541  noteNegotiationDone(anErr);
542  bail(anErr);
543 }
544 
545 void
547 {
548  Must(error); // or the recepient will not know there was a problem
549  Must(callback != NULL);
550  CbDialer *dialer = dynamic_cast<CbDialer*>(callback->getDialer());
551  Must(dialer);
552  dialer->answer().error = error;
553 
554  callBack();
555  // Our job is done. The callabck recepient will probably close the failed
556  // peer connection and try another peer or go direct (if possible). We
557  // can close the connection ourselves (our error notification would reach
558  // the recepient before the fd-closure notification), but we would rather
559  // minimize the number of fd-closure notifications and let the recepient
560  // manage the TCP state of the connection.
561 }
562 
563 void
565 {
566  debugs(83, 5, "TLS setup ended for " << serverConnection());
567 
569  // Do this now so that if we throw below, swanSong() assert that we _tried_
570  // to call back holds.
571  callback = NULL; // this should make done() true
572 
573  // remove close handler
574  comm_remove_close_handler(serverConnection()->fd, closeHandler);
575 
576  CbDialer *dialer = dynamic_cast<CbDialer*>(cb->getDialer());
577  Must(dialer);
578  dialer->answer().conn = serverConnection();
579  ScheduleCallHere(cb);
580 }
581 
582 void
584 {
585  // XXX: unregister fd-closure monitoring and CommSetSelect interest, if any
587  if (callback != NULL) { // paranoid: we have left the caller waiting
588  debugs(83, DBG_IMPORTANT, "BUG: Unexpected state while connecting to a cache_peer or origin server");
590  bail(anErr);
591  assert(!callback);
592  return;
593  }
594 }
595 
596 const char *
598 {
599  static MemBuf buf;
600  buf.reset();
601 
602  // TODO: redesign AsyncJob::status() API to avoid this
603  // id and stop reason reporting duplication.
604  buf.append(" [", 2);
605  if (stopReason != NULL) {
606  buf.append("Stopped, reason:", 16);
607  buf.appendf("%s",stopReason);
608  }
609  if (serverConn != NULL)
610  buf.appendf(" FD %d", serverConn->fd);
611  buf.appendf(" %s%u]", id.prefix(), id.value);
612  buf.terminate();
613 
614  return buf.content();
615 }
616 
617 #if USE_OPENSSL
620 {
621 public:
622  typedef void (Security::PeerConnector::*Method)(SBuf &object, int status);
623 
625  method_(method),
626  peerConnector_(pc) {}
627 
628  /* CallDialer API */
629  virtual bool canDial(AsyncCall &call) { return peerConnector_.valid(); }
630  virtual void dial(AsyncCall &call) { ((&(*peerConnector_))->*method_)(object, status); }
633 };
634 
635 void
637 {
638  AsyncCall::Pointer certCallback = asyncCall(81, 4,
639  "Security::PeerConnector::certDownloadingDone",
641 
642  const Downloader *csd = (request ? dynamic_cast<const Downloader*>(request->downloader.valid()) : nullptr);
643  Downloader *dl = new Downloader(url, certCallback, XactionInitiator::initCertFetcher, csd ? csd->nestedLevel() + 1 : 1);
644  AsyncJob::Start(dl);
645 }
646 
647 void
649 {
650  ++certsDownloads;
651  debugs(81, 5, "Certificate downloading status: " << downloadStatus << " certificate size: " << obj.length());
652 
653  // get ServerBio from SSL object
654  const int fd = serverConnection()->fd;
655  Security::SessionPointer session(fd_table[fd].ssl);
656  BIO *b = SSL_get_rbio(session.get());
657  Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
658 
659  // Parse Certificate. Assume that it is in DER format.
660  // According to RFC 4325:
661  // The server must provide a DER encoded certificate or a collection
662  // collection of certificates in a "certs-only" CMS message.
663  // The applications MUST accept DER encoded certificates and SHOULD
664  // be able to accept collection of certificates.
665  // TODO: support collection of certificates
666  const unsigned char *raw = (const unsigned char*)obj.rawContent();
667  if (X509 *cert = d2i_X509(NULL, &raw, obj.length())) {
668  char buffer[1024];
669  debugs(81, 5, "Retrieved certificate: " << X509_NAME_oneline(X509_get_subject_name(cert), buffer, 1024));
670  ContextPointer ctx(getTlsContext());
671  const Security::CertList &certsList = srvBio->serverCertificatesIfAny();
672  if (const char *issuerUri = Ssl::uriOfIssuerIfMissing(cert, certsList, ctx)) {
673  urlsOfMissingCerts.push(SBuf(issuerUri));
674  }
675  Ssl::SSL_add_untrusted_cert(session.get(), cert);
676  }
677 
678  // Check if there are URIs to download from and if yes start downloading
679  // the first in queue.
680  if (urlsOfMissingCerts.size() && certsDownloads <= MaxCertsDownloads) {
681  startCertDownloading(urlsOfMissingCerts.front());
682  urlsOfMissingCerts.pop();
683  return;
684  }
685 
686  srvBio->holdRead(false);
687  negotiateSsl();
688 }
689 
690 bool
692 {
693  // Check for nested SSL certificates downloads. For example when the
694  // certificate located in an SSL site which requires to download a
695  // a missing certificate (... from an SSL site which requires to ...).
696 
697  const Downloader *csd = (request ? request->downloader.get() : nullptr);
698  if (csd && csd->nestedLevel() >= MaxNestedDownloads)
699  return false;
700 
701  const int fd = serverConnection()->fd;
702  Security::SessionPointer session(fd_table[fd].ssl);
703  BIO *b = SSL_get_rbio(session.get());
704  Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
705  const Security::CertList &certs = srvBio->serverCertificatesIfAny();
706 
707  if (certs.size()) {
708  debugs(83, 5, "SSL server sent " << certs.size() << " certificates");
709  ContextPointer ctx(getTlsContext());
710  Ssl::missingChainCertificatesUrls(urlsOfMissingCerts, certs, ctx);
711  if (urlsOfMissingCerts.size()) {
712  startCertDownloading(urlsOfMissingCerts.front());
713  urlsOfMissingCerts.pop();
714  return true;
715  }
716  }
717 
718  return false;
719 }
720 #endif //USE_OPENSSL
721 
virtual bool doneAll() const
whether positive goal has been reached
Definition: AsyncJob.cc:96
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:68
#define fd_table
Definition: fde.h:157
#define COMM_SELECT_READ
Definition: defines.h:36
#define assert(EX)
Definition: assert.h:17
void const char HLPCB * callback
Definition: stub_helper.cc:16
RecvdErrors errors
The list of parsed errors.
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:57
void connectionClosed(const char *reason)
Inform us that the connection is closed. Does the required clean-up.
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
int ssl_ex_index_server
virtual const char * status() const
internal cleanup; do not call directly
CbcPointer< ErrorState > error
problem details (nil on success)
Definition: SBuf.h:86
void startCertDownloading(SBuf &url)
Start downloading procedure for the given URL.
struct SquidConfig::@124 ssl_client
PeerConnector(const Comm::ConnectionPointer &aServerConn, AsyncCall::Pointer &aCallback, const AccessLogEntryPointer &alp, const time_t timeout=0)
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
void error(char *format,...)
int i
Definition: membanger.c:49
CbcPointer< Security::PeerConnector > peerConnector_
The Security::PeerConnector object.
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
Missing intermediate certificates fetching code.
int ssl_ex_index_cert_error_check
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
CallDialer to allow use Downloader objects within PeerConnector class.
AsyncCall::Pointer callback
we call this with the results
A const & max(A const &lhs, A const &rhs)
CtoCpp1(X509_free, X509 *) typedef Security CtoCpp1(X509_CRL_free, X509_CRL *) typedef Security typedef std::list< Security::CertPointer CertList)
Definition: forward.h:95
time_t squid_curtime
Definition: stub_time.cc:17
bool holdRead() const
The read hold state.
Definition: bio.h:150
virtual void noteWantWrite()
AsyncCall * asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
void commCloseHandler(const CommCloseCbParams &params)
The comm_close callback handler.
static void Submit(Ssl::CertValidationRequest const &request, AsyncCall::Pointer &)
Submit crtd request message to external crtd server.
Definition: helper.cc:290
static Pointer Start(AsyncJob *job)
starts a freshly created job (i.e., makes the job asynchronous)
Definition: AsyncJob.cc:23
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:24
void const char HLPCB void * data
Definition: stub_helper.cc:16
CbDataList< Security::CertError > CertErrors
Holds a list of X.509 certificate errors.
Definition: forward.h:81
virtual CallDialer * getDialer()=0
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:404
Security::SessionPointer ssl
int fd
FD which the call was about. Set by the async call creator.
Definition: CommCalls.h:90
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
#define true
Definition: GnuRegex.c:234
#define DBG_IMPORTANT
Definition: Debug.h:46
bool CreateClientSession(const Security::ContextPointer &, const Comm::ConnectionPointer &, const char *squidCtx)
Definition: Session.cc:185
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:225
int ssl_ex_index_ssl_error_detail
bool push_back_unique(C const &element)
Definition: CbDataList.h:87
virtual void swanSong()
Definition: AsyncJob.h:54
void reset()
Definition: MemBuf.cc:132
void missingChainCertificatesUrls(std::queue< SBuf > &URIs, Security::CertList const &serverCertificates, const Security::ContextPointer &context)
Definition: support.cc:1071
#define COMM_SELECT_WRITE
Definition: defines.h:37
static void NegotiateSsl(int fd, void *data)
A wrapper for Comm::SetSelect() notifications.
virtual bool doneAll() const
whether positive goal has been reached
std::shared_ptr< SSL_CTX > ContextPointer
Definition: Context.h:28
bool allowed() const
Definition: Acl.h:141
virtual Security::EncryptorAnswer & answer()=0
gives PeerConnector access to the in-dialer answer
void sslCrtvdHandleReply(Ssl::CertValidationResponsePointer)
Process response from cert validator helper.
void handleNegotiateError(const int result)
void SSL_add_untrusted_cert(SSL *ssl, X509 *cert)
Definition: support.cc:1083
int ssl_ex_index_ssl_errors
virtual void start()
Preps connection and SSL state. Calls negotiate().
char * content()
start of the added data
Definition: MemBuf.h:41
struct SquidConfig::@99 Timeout
void const char * buf
Definition: stub_helper.cc:16
acl_access * cert_error
Definition: SquidConfig.h:513
unsigned int nestedLevel() const
The nested level of Downloader object (downloads inside downloads).
Definition: Downloader.h:57
const char * uriOfIssuerIfMissing(X509 *cert, Security::CertList const &serverCertificates, const Security::ContextPointer &context)
Definition: support.cc:1050
virtual void dial(AsyncCall &call)
#define SQUID_ERR_SSL_HANDSHAKE
Definition: support.h:42
Security::CertErrors * errors
The list of errors detected.
static ErrorState * NewForwarding(err_type, HttpRequestPointer &)
Creates a general request forwarding error with the right http_status.
Definition: errorpage.cc:552
std::string domainName
The server name.
allow_t const & fastCheck()
Definition: Checklist.cc:336
virtual bool canDial(AsyncCall &call)
#define ScheduleCallHere(call)
Definition: AsyncCall.h:166
static char server[MAXLINE]
void certDownloadingDone(SBuf &object, int status)
Called by Downloader after a certificate object downloaded.
Callback dialer API to allow PeerConnector to set the answer.
Definition: PeerConnector.h:71
Callback data to use with Downloader callbacks.
Definition: Downloader.h:35
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
size_t HttpReply *STUB StoreEntry const KeyScope scope const HttpRequestMethod & method
Definition: stub_store.cc:126
Method method_
The Security::PeerConnector method to dial.
PeerConnectorCertDownloaderDialer(Method method, Security::PeerConnector *pc)
Definition: MemBuf.h:23
const Security::CertErrors * sslErrors
SSL [certificate validation] errors, in undefined order.
Comm::ConnectionPointer conn
peer connection (secured on success)
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:961
virtual bool initialize(Security::SessionPointer &)
void * BIO_get_data(BIO *table)
Definition: bio.h:209
int xerrno
Definition: errorpage.h:149
CBDATA_NAMESPACED_CLASS_INIT(Security, PeerConnector)
virtual void start()
called by AsyncStart; do not call directly
Definition: AsyncJob.cc:43
#define acl_access
Definition: forward.h:44
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:988
static bool Enabled(const int section, const int level)
whether debugging the given section and the given level produces output
Definition: Debug.h:75
virtual void noteNegotiationError(const int result, const int ssl_error, const int ssl_lib_error)
const char * rawContent() const
Definition: SBuf.cc:519
void negotiateSsl()
Comm::SetSelect() callback. Direct calls tickle/resume negotiations.
Ssl::ErrorDetail * detail
Definition: errorpage.h:171
void setLibError(unsigned long lib_err_no)
Sets the low-level error returned by OpenSSL ERR_get_error()
Definition: ErrorDetail.h:55
Security::CertErrors * sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &, Ssl::ErrorDetail *&)
Check SSL errors returned from cert validator against sslproxy_cert_error access list.
RawPointerT< Pointer > RawPointer(const char *label, const Pointer &ptr)
convenience wrapper for creating RawPointerT<> objects
Definition: Debug.h:237
Config TheConfig
Definition: Config.cc:12
const char * ErrorString(const ErrorCode code)
Definition: forward.h:120
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:552
void bail(ErrorState *error)
Return an error to the PeerConnector caller.
class SquidConfig Config
Definition: SquidConfig.cc:12
#define NULL
Definition: types.h:166
A const & min(A const &lhs, A const &rhs)
time_t read
Definition: SquidConfig.h:102
virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const
assigns uninitialized adapted_request and url ALE components
const char * dash_str
std::shared_ptr< SSL > SessionPointer
Definition: Session.h:41
void terminate()
Definition: MemBuf.cc:250

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors