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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors