PeerOptions.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 #include "squid.h"
10 #include "base/Packable.h"
11 #include "Debug.h"
12 #include "fatal.h"
13 #include "globals.h"
14 #include "parser/Tokenizer.h"
15 #include "Parsing.h"
16 #include "security/PeerOptions.h"
17 
18 #if USE_OPENSSL
19 #include "ssl/support.h"
20 #endif
21 
23 
25 {
26  // init options consistent with an empty sslOptions
27  parseOptions();
28 }
29 
30 void
31 Security::PeerOptions::parse(const char *token)
32 {
33  if (!*token) {
34  // config says just "ssl" or "tls" (or "tls-")
35  encryptTransport = true;
36  return;
37  }
38 
39  if (strncmp(token, "disable", 7) == 0) {
40  clear();
41  return;
42  }
43 
44  if (strncmp(token, "cert=", 5) == 0) {
45  KeyData t;
46  t.privateKeyFile = t.certFile = SBuf(token + 5);
47  certs.emplace_back(t);
48  } else if (strncmp(token, "key=", 4) == 0) {
49  if (certs.empty() || certs.back().certFile.isEmpty()) {
50  fatal("cert= option must be set before key= is used.");
51  return;
52  }
53  KeyData &t = certs.back();
54  t.privateKeyFile = SBuf(token + 4);
55  } else if (strncmp(token, "version=", 8) == 0) {
56  debugs(0, DBG_PARSE_NOTE(1), "UPGRADE WARNING: SSL version= is deprecated. Use options= and tls-min-version= to limit protocols instead.");
57  sslVersion = xatoi(token + 8);
58  } else if (strncmp(token, "min-version=", 12) == 0) {
59  tlsMinVersion = SBuf(token + 12);
60  optsReparse = true;
61  } else if (strncmp(token, "options=", 8) == 0) {
62  sslOptions = SBuf(token + 8);
63  optsReparse = true;
64  } else if (strncmp(token, "cipher=", 7) == 0) {
65  sslCipher = SBuf(token + 7);
66  } else if (strncmp(token, "cafile=", 7) == 0) {
67  caFiles.emplace_back(SBuf(token + 7));
68  } else if (strncmp(token, "capath=", 7) == 0) {
69  caDir = SBuf(token + 7);
70 #if !USE_OPENSSL
71  debugs(3, DBG_PARSE_NOTE(1), "WARNING: capath= option requires --with-openssl.");
72 #endif
73  } else if (strncmp(token, "crlfile=", 8) == 0) {
74  crlFile = SBuf(token + 8);
75  loadCrlFile();
76  } else if (strncmp(token, "flags=", 6) == 0) {
77  if (parsedFlags != 0) {
78  debugs(3, DBG_PARSE_NOTE(1), "WARNING: Overwriting flags=" << sslFlags << " with " << SBuf(token + 6));
79  }
80  sslFlags = SBuf(token + 6);
82  } else if (strncmp(token, "default-ca=off", 14) == 0 || strncmp(token, "no-default-ca", 13) == 0) {
84  fatalf("ERROR: previous default-ca settings conflict with %s", token);
86  } else if (strncmp(token, "default-ca=on", 13) == 0 || strncmp(token, "default-ca", 10) == 0) {
88  fatalf("ERROR: previous default-ca settings conflict with %s", token);
90  } else if (strncmp(token, "domain=", 7) == 0) {
91  sslDomain = SBuf(token + 7);
92  } else if (strncmp(token, "no-npn", 6) == 0) {
93  flags.tlsNpn = false;
94  } else {
95  debugs(3, DBG_CRITICAL, "ERROR: Unknown TLS option '" << token << "'");
96  return;
97  }
98 
99  encryptTransport = true;
100 }
101 
102 void
103 Security::PeerOptions::dumpCfg(Packable *p, const char *pfx) const
104 {
105  if (!encryptTransport) {
106  p->appendf(" %sdisable", pfx);
107  return; // no other settings are relevant
108  }
109 
110  for (auto &i : certs) {
111  if (!i.certFile.isEmpty())
112  p->appendf(" %scert=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(i.certFile));
113 
114  if (!i.privateKeyFile.isEmpty() && i.privateKeyFile != i.certFile)
115  p->appendf(" %skey=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(i.privateKeyFile));
116  }
117 
118  if (!sslOptions.isEmpty())
119  p->appendf(" %soptions=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslOptions));
120 
121  if (!sslCipher.isEmpty())
122  p->appendf(" %scipher=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslCipher));
123 
124  for (auto i : caFiles) {
125  p->appendf(" %scafile=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(i));
126  }
127 
128  if (!caDir.isEmpty())
129  p->appendf(" %scapath=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(caDir));
130 
131  if (!crlFile.isEmpty())
132  p->appendf(" %scrlfile=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(crlFile));
133 
134  if (!sslFlags.isEmpty())
135  p->appendf(" %sflags=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslFlags));
136 
137  if (flags.tlsDefaultCa.configured()) {
138  // default ON for peers / upstream servers
139  // default OFF for listening ports
140  if (flags.tlsDefaultCa)
141  p->appendf(" %sdefault-ca", pfx);
142  else
143  p->appendf(" %sdefault-ca=off", pfx);
144  }
145 
146  if (!flags.tlsNpn)
147  p->appendf(" %sno-npn", pfx);
148 }
149 
150 void
152 {
153  if (!tlsMinVersion.isEmpty()) {
155  int64_t v = 0;
157  if (tok.skip('1') && tok.skip('.') && tok.int64(v, 10, false, 1) && v <= 3) {
158  // only account for TLS here - SSL versions are handled by options= parameter
159  // avoid affecting options= parameter in cachemgr config report
160  SBuf add;
161 #if USE_OPENSSL
162  if (v > 0)
163  add.append(":NO_TLSv1");
164  if (v > 1)
165  add.append(":NO_TLSv1_1");
166  if (v > 2)
167  add.append(":NO_TLSv1_2");
168 #elif USE_GNUTLS
169  if (v > 0)
170  add.append(":-VERS-TLS1.0");
171  if (v > 1)
172  add.append(":-VERS-TLS1.1");
173  if (v > 2)
174  add.append(":-VERS-TLS1.2");
175 #endif
176 
177  if (!tlsMinOptions.isEmpty())
178  add.chop(1); // remove the initial ':'
179  tlsMinOptions.append(add);
180  optsReparse = true;
181 
182  } else {
183  debugs(0, DBG_PARSE_NOTE(1), "WARNING: Unknown TLS minimum version: " << tlsMinVersion);
184  }
185 
186  return;
187  }
188 
189  if (sslVersion > 2) {
190  // backward compatibility hack for sslversion= configuration
191  // only use if tls-min-version=N.N is not present
192  // values 0-2 for auto and SSLv2 are not supported any longer.
193  // Do it this way so we DO cause changes to options= in cachemgr config report
194  const char *add = nullptr;
195  switch (sslVersion) {
196  case 3:
197 #if USE_OPENSSL
198  add = ":NO_TLSv1:NO_TLSv1_1:NO_TLSv1_2:NO_TLSv1_3";
199 #elif USE_GNUTLS
200  add = ":-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.2:-VERS-TLS1.3";
201 #endif
202  break;
203  case 4:
204 #if USE_OPENSSL
205  add = ":NO_SSLv3:NO_TLSv1_1:NO_TLSv1_2:NO_TLSv1_3";
206 #elif USE_GNUTLS
207  add = ":+VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.2:-VERS-TLS1.3";
208 #endif
209  break;
210  case 5:
211 #if USE_OPENSSL
212  add = ":NO_SSLv3:NO_TLSv1:NO_TLSv1_2:NO_TLSv1_3";
213 #elif USE_GNUTLS
214  add = ":-VERS-TLS1.0:+VERS-TLS1.1:-VERS-TLS1.2:-VERS-TLS1.3";
215 #endif
216  break;
217  case 6:
218 #if USE_OPENSSL
219  add = ":NO_SSLv3:NO_TLSv1:NO_TLSv1_1:NO_TLSv1_3";
220 #elif USE_GNUTLS
221  add = ":-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.3";
222 #endif
223  break;
224  default: // nothing
225  break;
226  }
227  if (add) {
228  if (sslOptions.isEmpty())
229  sslOptions.append(add+1, strlen(add+1));
230  else
231  sslOptions.append(add, strlen(add));
232  optsReparse = true;
233  }
234  sslVersion = 0; // prevent sslOptions being repeatedly appended
235  }
236 }
237 
240 {
242 #if USE_OPENSSL
243  Ssl::Initialize();
244 
245  SSL_CTX *t = SSL_CTX_new(TLS_client_method());
246  if (!t) {
247  const auto x = ERR_get_error();
248  fatalf("Failed to allocate TLS client context: %s\n", Security::ErrorString(x));
249  }
250  ctx = convertContextFromRawPtr(t);
251 
252 #elif USE_GNUTLS
253  // Initialize for X.509 certificate exchange
254  gnutls_certificate_credentials_t t;
255  if (const int x = gnutls_certificate_allocate_credentials(&t)) {
256  fatalf("Failed to allocate TLS client context: %s\n", Security::ErrorString(x));
257  }
258  ctx = convertContextFromRawPtr(t);
259 
260 #else
261  debugs(83, 1, "WARNING: Failed to allocate TLS client context: No TLS library");
262 
263 #endif
264 
265  return ctx;
266 }
267 
270 {
272 
274  if (t) {
275  if (setOptions)
277 #if USE_OPENSSL
278  // XXX: temporary performance regression. c_str() data copies and prevents this being a const method
280 #endif
281  updateContextNpn(t);
282  updateContextCa(t);
283  updateContextCrl(t);
285  }
286 
287  return t;
288 }
289 
290 #if USE_OPENSSL
291 static struct ssl_option {
293  const char *name;
294  long value;
295 
296 } ssl_options[] = {
297 
298 #if SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
299  {
300  "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
301  },
302 #endif
303 #if SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
304  {
305  "SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
306  },
307 #endif
308 #if SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
309  {
310  "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
311  },
312 #endif
313 #if SSL_OP_SSLEAY_080_CLIENT_DH_BUG
314  {
315  "SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG
316  },
317 #endif
318 #if SSL_OP_TLS_D5_BUG
319  {
320  "TLS_D5_BUG", SSL_OP_TLS_D5_BUG
321  },
322 #endif
323 #if SSL_OP_TLS_BLOCK_PADDING_BUG
324  {
325  "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG
326  },
327 #endif
328 #if SSL_OP_TLS_ROLLBACK_BUG
329  {
330  "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG
331  },
332 #endif
333 #if SSL_OP_ALL
334  {
335  "ALL", (long)SSL_OP_ALL
336  },
337 #endif
338 #if SSL_OP_SINGLE_DH_USE
339  {
340  "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE
341  },
342 #endif
343 #if SSL_OP_EPHEMERAL_RSA
344  {
345  "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA
346  },
347 #endif
348 #if SSL_OP_PKCS1_CHECK_1
349  {
350  "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1
351  },
352 #endif
353 #if SSL_OP_PKCS1_CHECK_2
354  {
355  "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2
356  },
357 #endif
358 #if SSL_OP_NETSCAPE_CA_DN_BUG
359  {
360  "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG
361  },
362 #endif
363 #if SSL_OP_NON_EXPORT_FIRST
364  {
365  "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST
366  },
367 #endif
368 #if SSL_OP_CIPHER_SERVER_PREFERENCE
369  {
370  "CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE
371  },
372 #endif
373 #if SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
374  {
375  "NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
376  },
377 #endif
378 #if SSL_OP_NO_SSLv3
379  {
380  "NO_SSLv3", SSL_OP_NO_SSLv3
381  },
382 #endif
383 #if SSL_OP_NO_TLSv1
384  {
385  "NO_TLSv1", SSL_OP_NO_TLSv1
386  },
387 #else
388  { "NO_TLSv1", 0 },
389 #endif
390 #if SSL_OP_NO_TLSv1_1
391  {
392  "NO_TLSv1_1", SSL_OP_NO_TLSv1_1
393  },
394 #else
395  { "NO_TLSv1_1", 0 },
396 #endif
397 #if SSL_OP_NO_TLSv1_2
398  {
399  "NO_TLSv1_2", SSL_OP_NO_TLSv1_2
400  },
401 #else
402  { "NO_TLSv1_2", 0 },
403 #endif
404 #if SSL_OP_NO_TLSv1_3
405  {
406  "NO_TLSv1_3", SSL_OP_NO_TLSv1_3
407  },
408 #else
409  { "NO_TLSv1_3", 0 },
410 #endif
411 #if SSL_OP_NO_COMPRESSION
412  {
413  "No_Compression", SSL_OP_NO_COMPRESSION
414  },
415 #endif
416 #if SSL_OP_NO_TICKET
417  {
418  "NO_TICKET", SSL_OP_NO_TICKET
419  },
420 #endif
421 #if SSL_OP_SINGLE_ECDH_USE
422  {
423  "SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE
424  },
425 #endif
426  {
427  "", 0
428  },
429  {
430  NULL, 0
431  }
432 };
433 #endif /* USE_OPENSSL */
434 
439 void
441 {
442  // do not allow repeated parsing when multiple contexts are created
443  // NP: we cannot use !parsedOptions because a nil value does have meaning there
444  if (!optsReparse)
445  return;
446  optsReparse = false;
447 
448  // combination of settings we have to set via parsedOptions.
449  // options= with override by tls-min-version=
450  SBuf str;
451  str.append(sslOptions);
452  str.append(tlsMinOptions);
453 
454 #if USE_OPENSSL
456  long op = 0;
457 
458  while (!tok.atEnd()) {
459  enum {
460  MODE_ADD, MODE_REMOVE
461  } mode;
462 
463  if (tok.skip('-') || tok.skip('!'))
464  mode = MODE_REMOVE;
465  else {
466  (void)tok.skip('+'); // default action is add. ignore if missing operator
467  mode = MODE_ADD;
468  }
469 
470  static const CharacterSet optChars = CharacterSet("TLS-option", "_") + CharacterSet::ALPHA + CharacterSet::DIGIT;
471  int64_t hex = 0;
472  SBuf option;
473  long value = 0;
474 
475  // Bug 4429: identify the full option name before determining text or numeric
476  if (tok.prefix(option, optChars)) {
477 
478  // find the named option in our supported set
479  for (struct ssl_option *opttmp = ssl_options; opttmp->name; ++opttmp) {
480  if (option.cmp(opttmp->name) == 0) {
481  value = opttmp->value;
482  break;
483  }
484  }
485 
486  // Special case.. hex specification
487  ::Parser::Tokenizer tmp(option);
488  if (!value && tmp.int64(hex, 16, false) && tmp.atEnd()) {
489  value = hex;
490  }
491  }
492 
493  if (value) {
494  switch (mode) {
495  case MODE_ADD:
496  op |= value;
497  break;
498  case MODE_REMOVE:
499  op &= ~value;
500  break;
501  }
502  } else {
503  debugs(83, DBG_PARSE_NOTE(1), "ERROR: Unknown TLS option " << option);
504  }
505 
506  static const CharacterSet delims("TLS-option-delim",":,");
507  if (!tok.skipAll(delims) && !tok.atEnd()) {
508  fatalf("Unknown TLS option '" SQUIDSBUFPH "'", SQUIDSBUFPRINT(tok.remaining()));
509  }
510 
511  }
512 
513 #if SSL_OP_NO_SSLv2
514  // compliance with RFC 6176: Prohibiting Secure Sockets Layer (SSL) Version 2.0
515  op = op | SSL_OP_NO_SSLv2;
516 #endif
517  parsedOptions = op;
518 
519 #elif USE_GNUTLS
520  if (str.isEmpty()) {
521  parsedOptions.reset();
522  return;
523  }
524 
525  const char *err = nullptr;
526  const char *priorities = str.c_str();
527  gnutls_priority_t op;
528  int x = gnutls_priority_init(&op, priorities, &err);
529  if (x != GNUTLS_E_SUCCESS) {
530  fatalf("(%s) in TLS options '%s'", ErrorString(x), err);
531  }
532  parsedOptions = Security::ParsedOptions(op, [](gnutls_priority_t p) {
533  debugs(83, 5, "gnutls_priority_deinit p=" << (void*)p);
534  gnutls_priority_deinit(p);
535  });
536 #endif
537 }
538 
542 long
544 {
545  if (sslFlags.isEmpty())
546  return 0;
547 
548  static struct {
549  SBuf label;
550  long mask;
551  } flagTokens[] = {
552  { SBuf("NO_DEFAULT_CA"), SSL_FLAG_NO_DEFAULT_CA },
553  { SBuf("DELAYED_AUTH"), SSL_FLAG_DELAYED_AUTH },
554  { SBuf("DONT_VERIFY_PEER"), SSL_FLAG_DONT_VERIFY_PEER },
555  { SBuf("DONT_VERIFY_DOMAIN"), SSL_FLAG_DONT_VERIFY_DOMAIN },
556  { SBuf("NO_SESSION_REUSE"), SSL_FLAG_NO_SESSION_REUSE },
557 #if X509_V_FLAG_CRL_CHECK
558  { SBuf("VERIFY_CRL"), SSL_FLAG_VERIFY_CRL },
559  { SBuf("VERIFY_CRL_ALL"), SSL_FLAG_VERIFY_CRL_ALL },
560 #endif
561  { SBuf(), 0 }
562  };
563 
565  static const CharacterSet delims("Flag-delimiter", ":,");
566 
567  long fl = 0;
568  do {
569  long found = 0;
570  for (size_t i = 0; flagTokens[i].mask; ++i) {
571  if (tok.skip(flagTokens[i].label)) {
572  found = flagTokens[i].mask;
573  break;
574  }
575  }
576  if (!found)
577  fatalf("Unknown TLS flag '" SQUIDSBUFPH "'", SQUIDSBUFPRINT(tok.remaining()));
578  if (found == SSL_FLAG_NO_DEFAULT_CA) {
580  fatal("ERROR: previous default-ca settings conflict with sslflags=NO_DEFAULT_CA");
581  debugs(83, DBG_PARSE_NOTE(2), "WARNING: flags=NO_DEFAULT_CA is deprecated. Use tls-default-ca=off instead.");
583  } else
584  fl |= found;
585  } while (tok.skipOne(delims));
586 
587  return fl;
588 }
589 
592 void
594 {
595  parsedCrl.clear();
596  if (crlFile.isEmpty())
597  return;
598 
599 #if USE_OPENSSL
600  BIO *in = BIO_new_file(crlFile.c_str(), "r");
601  if (!in) {
602  debugs(83, 2, "WARNING: Failed to open CRL file " << crlFile);
603  return;
604  }
605 
606  while (X509_CRL *crl = PEM_read_bio_X509_CRL(in,NULL,NULL,NULL)) {
607  parsedCrl.emplace_back(Security::CrlPointer(crl));
608  }
609  BIO_free(in);
610 #endif
611 }
612 
613 void
615 {
616  parseOptions();
617 #if USE_OPENSSL
618  SSL_CTX_set_options(ctx.get(), parsedOptions);
619 #elif USE_GNUTLS
620  // NP: GnuTLS uses 'priorities' which are set only per-session instead.
621 #endif
622 }
623 
624 #if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
625 // Dummy next_proto_neg callback
626 static int
627 ssl_next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
628 {
629  static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
630  (void)SSL_select_next_proto(out, outlen, in, inlen, supported_protos, sizeof(supported_protos));
631  return SSL_TLSEXT_ERR_OK;
632 }
633 #endif
634 
635 void
637 {
638  if (!flags.tlsNpn)
639  return;
640 
641 #if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
642  SSL_CTX_set_next_proto_select_cb(ctx.get(), &ssl_next_proto_cb, nullptr);
643 #endif
644 
645  // NOTE: GnuTLS does not support the obsolete NPN extension.
646  // it does support ALPN per-session, not per-context.
647 }
648 
649 static const char *
651 {
652  debugs(83, 8, "Setting default system Trusted CA. ctx=" << (void*)ctx.get());
653 #if USE_OPENSSL
654  if (SSL_CTX_set_default_verify_paths(ctx.get()) == 0)
655  return Security::ErrorString(ERR_get_error());
656 
657 #elif USE_GNUTLS
658  auto x = gnutls_certificate_set_x509_system_trust(ctx.get());
659  if (x < 0)
660  return Security::ErrorString(x);
661 
662 #endif
663  return nullptr;
664 }
665 
666 void
668 {
669  debugs(83, 8, "Setting CA certificate locations.");
670 #if USE_OPENSSL
671  if (const char *path = caDir.isEmpty() ? nullptr : caDir.c_str()) {
672  if (!SSL_CTX_load_verify_locations(ctx.get(), nullptr, path)) {
673  const auto x = ERR_get_error();
674  debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location " << path << ": " << Security::ErrorString(x));
675  }
676  }
677 #endif
678  for (auto i : caFiles) {
679 #if USE_OPENSSL
680  if (!SSL_CTX_load_verify_locations(ctx.get(), i.c_str(), nullptr)) {
681  const auto x = ERR_get_error();
682  debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location " <<
683  i << ": " << Security::ErrorString(x));
684  }
685 #elif USE_GNUTLS
686  const auto x = gnutls_certificate_set_x509_trust_file(ctx.get(), i.c_str(), GNUTLS_X509_FMT_PEM);
687  if (x < 0) {
688  debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location " <<
689  i << ": " << Security::ErrorString(x));
690  }
691 #endif
692  }
693 
694  if (!flags.tlsDefaultCa)
695  return;
696 
697  if (const char *err = loadSystemTrustedCa(ctx)) {
698  debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default trusted CA : " << err);
699  }
700 }
701 
702 void
704 {
705 #if USE_OPENSSL
706  bool verifyCrl = false;
707  X509_STORE *st = SSL_CTX_get_cert_store(ctx.get());
708  if (parsedCrl.size()) {
709  for (auto &i : parsedCrl) {
710  if (!X509_STORE_add_crl(st, i.get()))
711  debugs(83, 2, "WARNING: Failed to add CRL");
712  else
713  verifyCrl = true;
714  }
715  }
716 
717 #if X509_V_FLAG_CRL_CHECK
719  X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
720  else if (verifyCrl || (parsedFlags & SSL_FLAG_VERIFY_CRL))
721  X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK);
722 #endif
723 
724 #endif /* USE_OPENSSL */
725 }
726 
727 void
729 {
730 #if USE_OPENSSL
731 #if defined(X509_V_FLAG_PARTIAL_CHAIN)
732  const auto st = SSL_CTX_get_cert_store(ctx.get());
733  assert(st);
734  if (X509_STORE_set_flags(st, X509_V_FLAG_PARTIAL_CHAIN) != 1) {
735  debugs(83, DBG_IMPORTANT, "ERROR: Failed to enable trust in intermediate CA certificates: " <<
736  Security::ErrorString(ERR_get_error()));
737  }
738 #endif
739 #elif USE_GNUTLS
740  // Modern GnuTLS versions trust intermediate CA certificates by default.
741 #endif /* TLS library */
742 }
743 
744 void
746 {
747  parseOptions();
748 #if USE_OPENSSL
749  debugs(83, 5, "set OpenSSL options for session=" << s << ", parsedOptions=" << parsedOptions);
750  // XXX: Options already set before (via the context) are not cleared!
751  SSL_set_options(s.get(), parsedOptions);
752 
753 #elif USE_GNUTLS
754  int x;
755  SBuf errMsg;
756  if (!parsedOptions) {
757  debugs(83, 5, "set GnuTLS default priority/options for session=" << s);
758  x = gnutls_set_default_priority(s.get());
759  static const SBuf defaults("default");
760  errMsg = defaults;
761  } else {
762  debugs(83, 5, "set GnuTLS session=" << s << ", options='" << sslOptions << ":" << tlsMinOptions << "'");
763  x = gnutls_priority_set(s.get(), parsedOptions.get());
764  errMsg = sslOptions;
765  }
766 
767  if (x != GNUTLS_E_SUCCESS) {
768  debugs(83, DBG_IMPORTANT, "ERROR: session=" << s << " Failed to set TLS options (" << errMsg << ":" << tlsMinVersion << "). error: " << Security::ErrorString(x));
769  }
770 #endif
771 }
772 
773 void
775 {
776  while(const char *token = ConfigParser::NextToken())
777  opt->parse(token);
778  opt->parseOptions();
779 }
780 
#define SSL_FLAG_VERIFY_CRL
Definition: forward.h:50
int xatoi(const char *token)
Definition: Parsing.cc:43
#define assert(EX)
Definition: assert.h:17
SBuf certFile
path of file containing PEM format X.509 certificate
Definition: KeyData.h:27
virtual void clear()
reset the configuration details to default
Definition: PeerOptions.h:39
Definition: SBuf.h:86
Security::ContextPointer convertContextFromRawPtr(T ctx) const
Definition: PeerOptions.h:108
int i
Definition: membanger.c:49
void updateContextCrl(Security::ContextPointer &)
setup the CRL details for the given context
Definition: PeerOptions.cc:703
SBuf & append(const SBuf &S)
Definition: SBuf.cc:195
Security::ParsedOptions parsedOptions
Definition: PeerOptions.h:94
bool encryptTransport
whether transport encryption (TLS/SSL) is to be used on connections to the peer
Definition: PeerOptions.h:144
SBuf & chop(size_type pos, size_type n=npos)
Definition: SBuf.cc:540
Security::CertRevokeList parsedCrl
CRL to use when verifying the remote end certificate.
Definition: PeerOptions.h:104
void clear()
Definition: SBuf.cc:178
YesNoNone tlsDefaultCa
whether to use the system default Trusted CA when verifying the remote end certificate ...
Definition: PeerOptions.h:136
bool isEmpty() const
Definition: SBuf.h:420
SBuf sslOptions
library-specific options string
Definition: PeerOptions.h:77
long ParsedOptions
Definition: forward.h:129
#define DBG_CRITICAL
Definition: Debug.h:45
bool tlsNpn
whether to use the TLS NPN extension on these connections
Definition: PeerOptions.h:139
char * p
Definition: membanger.c:43
#define DBG_PARSE_NOTE(x)
Definition: Debug.h:50
static const CharacterSet ALPHA
Definition: CharacterSet.h:73
#define SSL_FLAG_NO_DEFAULT_CA
Definition: forward.h:45
#define SSL_FLAG_DONT_VERIFY_PEER
Definition: forward.h:47
TLS squid.conf settings for a remote server peer.
Definition: PeerOptions.h:22
bool optsReparse
whether parsedOptions content needs to be regenerated
Definition: PeerOptions.h:97
void updateContextNpn(Security::ContextPointer &)
setup the NPN extension details for the given context
Definition: PeerOptions.cc:636
SBuf privateKeyFile
path of file containing private key in PEM format
Definition: KeyData.h:28
#define TLS_client_method
Definition: openssl.h:154
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
#define SSL_FLAG_DONT_VERIFY_DOMAIN
Definition: forward.h:48
void EVH void * arg
Definition: stub_event.cc:16
const char * name
Definition: PeerOptions.cc:293
void updateContextCa(Security::ContextPointer &)
setup the CA details for the given context
Definition: PeerOptions.cc:667
static const char * loadSystemTrustedCa(Security::ContextPointer &ctx)
Definition: PeerOptions.cc:650
virtual Security::ContextPointer createBlankContext() const
generate an unset security context object
Definition: PeerOptions.cc:239
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
#define DBG_IMPORTANT
Definition: Debug.h:46
#define SSL_FLAG_DELAYED_AUTH
Definition: forward.h:46
void updateSessionOptions(Security::SessionPointer &)
setup any library-specific options that can be set for the given session
Definition: PeerOptions.cc:745
static const CharacterSet DIGIT
Definition: CharacterSet.h:81
PeerOptions ProxyOutgoingConfig
configuration options for DIRECT server access
Definition: PeerOptions.cc:22
void updateContextTrust(Security::ContextPointer &)
decide which CAs to trust
Definition: PeerOptions.cc:728
static struct ssl_option ssl_options[]
static char * NextToken()
bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, long flags)
initialize a TLS client context with OpenSSL specific settings
Definition: support.cc:531
SBuf crlFile
path of file containing Certificate Revoke List
Definition: PeerOptions.h:79
std::shared_ptr< SSL_CTX > ContextPointer
Definition: Context.h:29
void fatal(const char *message)
Definition: fatal.cc:28
const char * c_str()
Definition: SBuf.cc:526
const SBuf & remaining() const
the remaining unprocessed section of buffer
Definition: Tokenizer.h:44
optimized set of C chars, with quick membership test and merge support
Definition: CharacterSet.h:17
Security::ContextPointer createClientContext(bool setOptions)
generate a security client-context from these configured options
Definition: PeerOptions.cc:269
Definition: parse.c:160
bool skipOne(const CharacterSet &discardables)
Definition: Tokenizer.cc:151
void configure(bool beSet)
enables or disables the option; updating to &#39;configured&#39; state
Definition: YesNoNone.h:53
bool configured() const
Definition: YesNoNone.h:67
SBuf sslFlags
flags defining what TLS operations Squid performs
Definition: PeerOptions.h:82
bool skip(const SBuf &tokenToSkip)
Definition: Tokenizer.cc:179
virtual void parse(const char *)
parse a TLS squid.conf option
Definition: PeerOptions.cc:31
void Initialize()
Definition: support.cc:479
bool prefix(SBuf &returnedToken, const CharacterSet &tokenChars, SBuf::size_type limit=SBuf::npos)
Definition: Tokenizer.cc:81
bool atEnd() const
whether the end of the buffer has been reached
Definition: Tokenizer.h:41
SBuf tlsMinVersion
version label for minimum TLS version to permit
Definition: PeerOptions.h:85
SBuf caDir
path of directory containing a set of trusted Certificate Authorities
Definition: PeerOptions.h:78
void updateContextOptions(Security::ContextPointer &)
Setup the library specific &#39;options=&#39; parameters for the given context.
Definition: PeerOptions.cc:614
virtual void dumpCfg(Packable *, const char *pfx) const
output squid.conf syntax with &#39;pfx&#39; prefix on parameters for the stored settings
Definition: PeerOptions.cc:103
TLS certificate and private key details from squid.conf.
Definition: KeyData.h:20
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:264
#define SSL_FLAG_NO_SESSION_REUSE
Definition: forward.h:49
std::list< SBuf > caFiles
paths of files containing trusted Certificate Authority
Definition: PeerOptions.h:103
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
struct Security::PeerOptions::flags_ flags
SBuf::size_type skipAll(const CharacterSet &discardables)
Definition: Tokenizer.cc:139
std::list< Security::KeyData > certs
details from the cert= and file= config parameters
Definition: PeerOptions.h:102
set of options we can parse and what they map to
Definition: PeerOptions.cc:292
#define SQUIDSBUFPH
Definition: SBuf.h:31
void updateTlsVersionLimits()
sync the context options with tls-min-version=N configuration
Definition: PeerOptions.cc:151
void parseOptions()
parse and verify the [tls-]options= string in sslOptions
Definition: PeerOptions.cc:440
void parse_securePeerOptions(Security::PeerOptions *opt)
Definition: PeerOptions.cc:774
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
const char * ErrorString(const ErrorCode code)
Definition: forward.h:96
#define NULL
Definition: types.h:166
long parsedFlags
parsed value of sslFlags
Definition: PeerOptions.h:100
#define SSL_FLAG_VERIFY_CRL_ALL
Definition: forward.h:51
std::shared_ptr< SSL > SessionPointer
Definition: Session.h:44
bool int64(int64_t &result, int base=0, bool allowSign=true, SBuf::size_type limit=SBuf::npos)
Definition: Tokenizer.cc:228

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors