PeerOptions.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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/Stream.h"
12#include "fatal.h"
13#include "globals.h"
14#include "parser/Tokenizer.h"
15#include "Parsing.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
30}
31
32void
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), "WARNING: UPGRADE: 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
104void
105Security::PeerOptions::dumpCfg(std::ostream &os, const char *pfx) const
106{
107 if (!encryptTransport) {
108 os << ' ' << pfx << "disable";
109 return; // no other settings are relevant
110 }
111
112 for (auto &i : certs) {
113 if (!i.certFile.isEmpty())
114 os << ' ' << pfx << "cert=" << i.certFile;
115
116 if (!i.privateKeyFile.isEmpty() && i.privateKeyFile != i.certFile)
117 os << ' ' << pfx << "key=" << i.privateKeyFile;
118 }
119
120 if (!sslOptions.isEmpty())
121 os << ' ' << pfx << "options=" << sslOptions;
122
123 if (!sslCipher.isEmpty())
124 os << ' ' << pfx << "cipher=" << sslCipher;
125
126 for (auto i : caFiles) {
127 os << ' ' << pfx << "cafile=" << i;
128 }
129
130 if (!caDir.isEmpty())
131 os << ' ' << pfx << "capath=" << caDir;
132
133 if (!crlFile.isEmpty())
134 os << ' ' << pfx << "crlfile=" << crlFile;
135
136 if (!sslFlags.isEmpty())
137 os << ' ' << pfx << "flags=" << 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 os << ' ' << pfx << "default-ca";
144 else
145 os << ' ' << pfx << "default-ca=off";
146 }
147
148 if (!flags.tlsNpn)
149 os << ' ' << pfx << "no-npn";
150}
151
152void
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
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
294static struct ssl_option {
295 const char *name;
297
298} ssl_options[] = {
299
300#if defined(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 defined(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 defined(SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
311 {
312 "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
313 },
314#endif
315#if defined(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 defined(SSL_OP_TLS_D5_BUG)
321 {
322 "TLS_D5_BUG", SSL_OP_TLS_D5_BUG
323 },
324#endif
325#if defined(SSL_OP_TLS_BLOCK_PADDING_BUG)
326 {
327 "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG
328 },
329#endif
330#if defined(SSL_OP_TLS_ROLLBACK_BUG)
331 {
332 "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG
333 },
334#endif
335#if defined(SSL_OP_ALL)
336 {
337 "ALL", SSL_OP_ALL
338 },
339#endif
340#if defined(SSL_OP_SINGLE_DH_USE)
341 {
342 "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE
343 },
344#endif
345#if defined(SSL_OP_EPHEMERAL_RSA)
346 {
347 "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA
348 },
349#endif
350#if defined(SSL_OP_PKCS1_CHECK_1)
351 {
352 "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1
353 },
354#endif
355#if defined(SSL_OP_PKCS1_CHECK_2)
356 {
357 "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2
358 },
359#endif
360#if defined(SSL_OP_NETSCAPE_CA_DN_BUG)
361 {
362 "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG
363 },
364#endif
365#if defined(SSL_OP_NON_EXPORT_FIRST)
366 {
367 "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST
368 },
369#endif
370#if defined(SSL_OP_CIPHER_SERVER_PREFERENCE)
371 {
372 "CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE
373 },
374#endif
375#if defined(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 defined(SSL_OP_NO_SSLv3)
381 {
382 "NO_SSLv3", SSL_OP_NO_SSLv3
383 },
384#endif
385#if defined(SSL_OP_NO_TLSv1)
386 {
387 "NO_TLSv1", SSL_OP_NO_TLSv1
388 },
389#else
390 { "NO_TLSv1", 0 },
391#endif
392#if defined(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 defined(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 defined(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 defined(SSL_OP_NO_COMPRESSION)
414 {
415 "No_Compression", SSL_OP_NO_COMPRESSION
416 },
417#endif
418#if defined(SSL_OP_NO_TICKET)
419 {
420 "NO_TICKET", SSL_OP_NO_TICKET
421 },
422#endif
423#if defined(SSL_OP_SINGLE_ECDH_USE)
424 {
425 "SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE
426 },
427#endif
428 {
429 "", 0
430 },
431 {
432 nullptr, 0
433 }
435#endif /* USE_OPENSSL */
436
441void
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 ParsedOptions 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 ParsedOptions value = 0;
476 bool found = false;
477
478 // Bug 4429: identify the full option name before determining text or numeric
479 if (tok.prefix(option, optChars)) {
480
481 // find the named option in our supported set
482 for (struct ssl_option *opttmp = ssl_options; opttmp->name; ++opttmp) {
483 if (option.cmp(opttmp->name) == 0) {
484 value = opttmp->value;
485 found = true;
486 break;
487 }
488 }
489
490 // Special case.. hex specification
491 ::Parser::Tokenizer tmp(option);
492 if (!found && tmp.int64(hex, 16, false) && tmp.atEnd()) {
493 value = hex;
494 found = true;
495 }
496 }
497
498 if (value) {
499 switch (mode) {
500 case MODE_ADD:
501 op |= value;
502 break;
503 case MODE_REMOVE:
504 op &= ~value;
505 break;
506 }
507 } else {
508 debugs(83, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: " << (found?"Unsupported":"Unknown") << " TLS option " << option);
509 }
510
511 static const CharacterSet delims("TLS-option-delim",":,");
512 if (!tok.skipAll(delims) && !tok.atEnd()) {
513 fatalf("Unknown TLS option '" SQUIDSBUFPH "'", SQUIDSBUFPRINT(tok.remaining()));
514 }
515
516 }
517
518#if defined(SSL_OP_NO_SSLv2)
519 // compliance with RFC 6176: Prohibiting Secure Sockets Layer (SSL) Version 2.0
520 if (SSL_OP_NO_SSLv2)
521 op |= SSL_OP_NO_SSLv2;
522#endif
523 parsedOptions = op;
524
525#elif USE_GNUTLS
526 if (str.isEmpty()) {
527 parsedOptions.reset();
528 return;
529 }
530
531 const char *err = nullptr;
532 const char *priorities = str.c_str();
533 gnutls_priority_t op;
534 const auto x = gnutls_priority_init(&op, priorities, &err);
535 if (x != GNUTLS_E_SUCCESS) {
536 fatalf("(%s) in TLS options '%s'", ErrorString(x), err);
537 }
538 parsedOptions = Security::ParsedOptions(op, [](gnutls_priority_t p) {
539 debugs(83, 5, "gnutls_priority_deinit p=" << (void*)p);
540 gnutls_priority_deinit(p);
541 });
542#endif
543}
544
550{
551 if (sslFlags.isEmpty())
552 return 0;
553
554 static struct {
555 SBuf label;
556 ParsedPortFlags mask;
557 } flagTokens[] = {
558 { SBuf("NO_DEFAULT_CA"), SSL_FLAG_NO_DEFAULT_CA },
559 { SBuf("DELAYED_AUTH"), SSL_FLAG_DELAYED_AUTH },
560 { SBuf("DONT_VERIFY_PEER"), SSL_FLAG_DONT_VERIFY_PEER },
561 { SBuf("CONDITIONAL_AUTH"), SSL_FLAG_CONDITIONAL_AUTH },
562 { SBuf("DONT_VERIFY_DOMAIN"), SSL_FLAG_DONT_VERIFY_DOMAIN },
563 { SBuf("NO_SESSION_REUSE"), SSL_FLAG_NO_SESSION_REUSE },
564#if X509_V_FLAG_CRL_CHECK
565 { SBuf("VERIFY_CRL"), SSL_FLAG_VERIFY_CRL },
566 { SBuf("VERIFY_CRL_ALL"), SSL_FLAG_VERIFY_CRL_ALL },
567#endif
568 { SBuf(), 0 }
569 };
570
571 ::Parser::Tokenizer tok(sslFlags);
572 static const CharacterSet delims("Flag-delimiter", ":,");
573
574 ParsedPortFlags fl = 0;
575 do {
576 ParsedPortFlags found = 0;
577 for (size_t i = 0; flagTokens[i].mask; ++i) {
578 // XXX: skips FOO in FOOBAR, missing merged flags and trailing typos
579 if (tok.skip(flagTokens[i].label)) {
580 found = flagTokens[i].mask;
581 break;
582 }
583 }
584 if (!found)
585 fatalf("Unknown TLS flag '" SQUIDSBUFPH "'", SQUIDSBUFPRINT(tok.remaining()));
586 if (found == SSL_FLAG_NO_DEFAULT_CA) {
587 if (flags.tlsDefaultCa.configured() && flags.tlsDefaultCa)
588 fatal("ERROR: previous default-ca settings conflict with sslflags=NO_DEFAULT_CA");
589 debugs(83, DBG_PARSE_NOTE(2), "WARNING: flags=NO_DEFAULT_CA is deprecated. Use tls-default-ca=off instead.");
590 flags.tlsDefaultCa.configure(false);
591 } else
592 fl |= found;
593 } while (tok.skipOne(delims));
594
595 const auto mutuallyExclusive =
599 typedef std::bitset<sizeof(decltype(fl))> ParsedPortFlagBits;
600 if (ParsedPortFlagBits(fl & mutuallyExclusive).count() > 1) {
602 throw TextException("CONDITIONAL_AUTH is not compatible with NO_DEFAULT_CA and DELAYED_AUTH flags", Here());
603 debugs(83, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: Mixtures of incompatible TLS flags" <<
604 " are deprecated and will become a fatal configuration error");
605 }
606
607 return fl;
608}
609
612void
614{
615 parsedCrl.clear();
616 if (crlFile.isEmpty())
617 return;
618
619#if USE_OPENSSL
620 BIO *in = BIO_new_file(crlFile.c_str(), "r");
621 if (!in) {
622 debugs(83, 2, "WARNING: Failed to open CRL file " << crlFile);
623 return;
624 }
625
626 while (X509_CRL *crl = PEM_read_bio_X509_CRL(in,nullptr,nullptr,nullptr)) {
627 parsedCrl.emplace_back(Security::CrlPointer(crl));
628 }
629 BIO_free(in);
630#endif
631}
632
633void
635{
636 parseOptions();
637#if USE_OPENSSL
638 SSL_CTX_set_options(ctx.get(), parsedOptions);
639#elif USE_GNUTLS
640 // NP: GnuTLS uses 'priorities' which are set only per-session instead.
641 (void)ctx;
642#else
643 (void)ctx;
644#endif
645}
646
647#if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
648// Dummy next_proto_neg callback
649static int
650ssl_next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void * /* arg */)
651{
652 static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
653 (void)SSL_select_next_proto(out, outlen, in, inlen, supported_protos, sizeof(supported_protos));
654 return SSL_TLSEXT_ERR_OK;
655}
656#endif
657
658void
660{
661 if (!flags.tlsNpn)
662 return;
663
664#if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
665 SSL_CTX_set_next_proto_select_cb(ctx.get(), &ssl_next_proto_cb, nullptr);
666#else
667 // NOTE: GnuTLS does not support the obsolete NPN extension.
668 // it does support ALPN per-session, not per-context.
669 (void)ctx;
670#endif
671}
672
673static const char *
675{
676 debugs(83, 8, "Setting default system Trusted CA. ctx=" << (void*)ctx.get());
677#if USE_OPENSSL
678 if (SSL_CTX_set_default_verify_paths(ctx.get()) == 0)
679 return Security::ErrorString(ERR_get_error());
680
681#elif USE_GNUTLS
682 auto x = gnutls_certificate_set_x509_system_trust(ctx.get());
683 if (x < 0)
684 return Security::ErrorString(x);
685
686#endif
687 return nullptr;
688}
689
690void
692{
693 debugs(83, 8, "Setting CA certificate locations.");
694#if USE_OPENSSL
695 if (const char *path = caDir.isEmpty() ? nullptr : caDir.c_str()) {
696 if (!SSL_CTX_load_verify_locations(ctx.get(), nullptr, path)) {
697 const auto x = ERR_get_error();
698 debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location " << path << ": " << Security::ErrorString(x));
699 }
700 }
701#endif
702 for (auto i : caFiles) {
703#if USE_OPENSSL
704 if (!SSL_CTX_load_verify_locations(ctx.get(), i.c_str(), nullptr)) {
705 const auto x = ERR_get_error();
706 debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location " <<
707 i << ": " << Security::ErrorString(x));
708 }
709#elif USE_GNUTLS
710 const auto x = gnutls_certificate_set_x509_trust_file(ctx.get(), i.c_str(), GNUTLS_X509_FMT_PEM);
711 if (x < 0) {
712 debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location " <<
713 i << ": " << Security::ErrorString(x));
714 }
715#endif
716 }
717
718 if (!flags.tlsDefaultCa)
719 return;
720
721 if (const char *err = loadSystemTrustedCa(ctx)) {
722 debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default trusted CA : " << err);
723 }
724}
725
726void
728{
729#if USE_OPENSSL
730 bool verifyCrl = false;
731 X509_STORE *st = SSL_CTX_get_cert_store(ctx.get());
732 if (parsedCrl.size()) {
733 for (auto &i : parsedCrl) {
734 if (!X509_STORE_add_crl(st, i.get()))
735 debugs(83, 2, "WARNING: Failed to add CRL");
736 else
737 verifyCrl = true;
738 }
739 }
740
741#if X509_V_FLAG_CRL_CHECK
742 if ((parsedFlags & SSL_FLAG_VERIFY_CRL_ALL))
743 X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
744 else if (verifyCrl || (parsedFlags & SSL_FLAG_VERIFY_CRL))
745 X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK);
746#endif
747
748#else /* USE_OPENSSL */
749 (void)ctx;
750#endif /* USE_OPENSSL */
751}
752
753void
755{
756#if USE_OPENSSL
757#if defined(X509_V_FLAG_PARTIAL_CHAIN)
758 const auto st = SSL_CTX_get_cert_store(ctx.get());
759 assert(st);
760 if (X509_STORE_set_flags(st, X509_V_FLAG_PARTIAL_CHAIN) != 1) {
761 debugs(83, DBG_IMPORTANT, "ERROR: Failed to enable trust in intermediate CA certificates: " <<
762 Security::ErrorString(ERR_get_error()));
763 }
764#endif
765#elif USE_GNUTLS
766 // Modern GnuTLS versions trust intermediate CA certificates by default.
767 (void)ctx;
768#else
769 (void)ctx;
770#endif /* TLS library */
771}
772
773void
775{
776 parseOptions();
777#if USE_OPENSSL
778 debugs(83, 5, "set OpenSSL options for session=" << s << ", parsedOptions=" << parsedOptions);
779 // XXX: Options already set before (via the context) are not cleared!
780 SSL_set_options(s.get(), parsedOptions);
781
782#elif USE_GNUTLS
783 LibErrorCode x;
784 SBuf errMsg;
785 if (!parsedOptions) {
786 debugs(83, 5, "set GnuTLS default priority/options for session=" << s);
787 x = gnutls_set_default_priority(s.get());
788 static const SBuf defaults("default");
789 errMsg = defaults;
790 } else {
791 debugs(83, 5, "set GnuTLS session=" << s << ", options='" << sslOptions << ":" << tlsMinOptions << "'");
792 x = gnutls_priority_set(s.get(), parsedOptions.get());
793 errMsg = sslOptions;
794 }
795
796 if (x != GNUTLS_E_SUCCESS) {
797 debugs(83, DBG_IMPORTANT, "ERROR: session=" << s << " Failed to set TLS options (" << errMsg << ":" << tlsMinVersion << "). error: " << Security::ErrorString(x));
798 }
799#else
800 (void)s;
801#endif
802}
803
804void
806{
807 while(const char *token = ConfigParser::NextToken())
808 opt->parse(token);
809 opt->parseOptions();
810}
811
#define Here()
source code location of the caller
Definition: Here.h:15
int xatoi(const char *token)
Definition: Parsing.cc:44
void parse_securePeerOptions(Security::PeerOptions *opt)
Definition: PeerOptions.cc:805
static const char * loadSystemTrustedCa(Security::ContextPointer &ctx)
Definition: PeerOptions.cc:674
static struct ssl_option ssl_options[]
#define SQUIDSBUFPH
Definition: SBuf.h:31
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
#define assert(EX)
Definition: assert.h:17
optimized set of C chars, with quick membership test and merge support
Definition: CharacterSet.h:18
static const CharacterSet DIGIT
Definition: CharacterSet.h:84
static const CharacterSet ALPHA
Definition: CharacterSet.h:76
static char * NextToken()
bool int64(int64_t &result, int base=0, bool allowSign=true, SBuf::size_type limit=SBuf::npos)
Definition: Tokenizer.cc:238
bool atEnd() const
whether the end of the buffer has been reached
Definition: Tokenizer.h:41
Definition: SBuf.h:94
const char * c_str()
Definition: SBuf.cc:516
SBuf & chop(size_type pos, size_type n=npos)
Definition: SBuf.cc:530
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:275
bool isEmpty() const
Definition: SBuf.h:431
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
TLS certificate and private key details from squid.conf.
Definition: KeyData.h:21
SBuf certFile
path of file containing PEM format X.509 certificate
Definition: KeyData.h:27
SBuf privateKeyFile
path of file containing private key in PEM format
Definition: KeyData.h:28
TLS squid.conf settings for a remote server peer.
Definition: PeerOptions.h:26
void updateContextCrl(Security::ContextPointer &)
setup the CRL details for the given context
Definition: PeerOptions.cc:727
ParsedPortFlags parseFlags()
Definition: PeerOptions.cc:549
Security::ContextPointer createClientContext(bool setOptions)
generate a security client-context from these configured options
Definition: PeerOptions.cc:271
virtual void parse(const char *)
parse a TLS squid.conf option
Definition: PeerOptions.cc:33
void updateContextCa(Security::ContextPointer &)
setup the CA details for the given context
Definition: PeerOptions.cc:691
void updateContextOptions(Security::ContextPointer &)
Setup the library specific 'options=' parameters for the given context.
Definition: PeerOptions.cc:634
void updateTlsVersionLimits()
sync the context options with tls-min-version=N configuration
Definition: PeerOptions.cc:153
virtual void dumpCfg(std::ostream &, const char *pfx) const
output squid.conf syntax with 'pfx' prefix on parameters for the stored settings
Definition: PeerOptions.cc:105
void updateContextTrust(Security::ContextPointer &)
decide which CAs to trust
Definition: PeerOptions.cc:754
void parseOptions()
parse and verify the [tls-]options= string in sslOptions
Definition: PeerOptions.cc:442
void updateContextNpn(Security::ContextPointer &)
setup the NPN extension details for the given context
Definition: PeerOptions.cc:659
virtual Security::ContextPointer createBlankContext() const
generate an unset security context object
Definition: PeerOptions.cc:241
void updateSessionOptions(Security::SessionPointer &)
setup any library-specific options that can be set for the given session
Definition: PeerOptions.cc:774
an std::runtime_error with thrower location info
Definition: TextException.h:21
#define DBG_PARSE_NOTE(x)
Definition: Stream.h:42
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
void fatal(const char *message)
Definition: fatal.cc:28
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
std::shared_ptr< SSL_CTX > ContextPointer
Definition: Context.h:29
uint64_t ParsedOptions
Definition: forward.h:192
std::shared_ptr< SSL > SessionPointer
Definition: Session.h:49
unsigned long LibErrorCode
TLS library-reported non-validation error.
Definition: forward.h:139
long ParsedPortFlags
Definition: forward.h:202
PeerOptions ProxyOutgoingConfig
configuration options for DIRECT server access
Definition: PeerOptions.cc:24
const char * ErrorString(const LibErrorCode code)
converts numeric LibErrorCode into a human-friendlier string
Definition: forward.h:150
bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, Security::ParsedPortFlags)
initialize a TLS client context with OpenSSL specific settings
Definition: support.cc:710
void Initialize()
Definition: support.cc:651
#define TLS_client_method
Definition: openssl.h:196
#define SSL_FLAG_CONDITIONAL_AUTH
Definition: forward.h:58
#define SSL_FLAG_DONT_VERIFY_PEER
Definition: forward.h:53
#define SSL_FLAG_NO_DEFAULT_CA
Definition: forward.h:51
#define SSL_FLAG_VERIFY_CRL
Definition: forward.h:56
#define SSL_FLAG_NO_SESSION_REUSE
Definition: forward.h:55
#define SSL_FLAG_DONT_VERIFY_DOMAIN
Definition: forward.h:54
#define SSL_FLAG_VERIFY_CRL_ALL
Definition: forward.h:57
#define SSL_FLAG_DELAYED_AUTH
Definition: forward.h:52
set of options we can parse and what they map to
Definition: PeerOptions.cc:294
const char * name
Definition: PeerOptions.cc:295
Security::ParsedOptions value
Definition: PeerOptions.cc:296
Definition: parse.c:160

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors