]> git.ipfire.org Git - thirdparty/squid.git/blame - src/security/PeerOptions.cc
Fixed CC directive ID check broken since r14130.1.60.
[thirdparty/squid.git] / src / security / PeerOptions.cc
CommitLineData
9a2f63e7 1/*
ef57eb7b 2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
9a2f63e7
AJ
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"
8250ca31 10#include "base/Packable.h"
0b0e0864 11#include "Debug.h"
6bd62757 12#include "fatal.h"
0b0e0864 13#include "globals.h"
1cc44095 14#include "parser/Tokenizer.h"
7f2cd2e8 15#include "Parsing.h"
9a2f63e7
AJ
16#include "security/PeerOptions.h"
17
18#if USE_OPENSSL
19#include "ssl/support.h"
20#endif
21
7e62a74f 22Security::PeerOptions Security::ProxyOutgoingConfig;
195f8adb 23
9a622f3e 24Security::PeerOptions::PeerOptions(const Security::PeerOptions &p) :
9a622f3e 25 sslOptions(p.sslOptions),
9a622f3e
AJ
26 caDir(p.caDir),
27 crlFile(p.crlFile),
28 sslCipher(p.sslCipher),
29 sslFlags(p.sslFlags),
30 sslDomain(p.sslDomain),
31 parsedOptions(p.parsedOptions),
32 parsedFlags(p.parsedFlags),
d1d72d43 33 certs(p.certs),
86a84cc0 34 caFiles(p.caFiles),
6b19d1f9 35 parsedCrl(p.parsedCrl),
9a622f3e
AJ
36 sslVersion(p.sslVersion),
37 encryptTransport(p.encryptTransport)
38{
8b253b83 39 memcpy(&flags, &p.flags, sizeof(flags));
9a622f3e
AJ
40}
41
0b0e0864
AJ
42void
43Security::PeerOptions::parse(const char *token)
44{
d4ab7b63
AJ
45 if (!*token) {
46 // config says just "ssl" or "tls" (or "tls-")
47 encryptTransport = true;
48 return;
49 }
50
41ee8990
AJ
51 if (strncmp(token, "disable", 7) == 0) {
52 clear();
d4ab7b63
AJ
53 return;
54 }
55
56 if (strncmp(token, "cert=", 5) == 0) {
d1d72d43
AJ
57 KeyData t;
58 t.privateKeyFile = t.certFile = SBuf(token + 5);
59 certs.emplace_back(t);
0b0e0864 60 } else if (strncmp(token, "key=", 4) == 0) {
d1d72d43
AJ
61 if (certs.empty() || certs.back().certFile.isEmpty()) {
62 debugs(3, DBG_PARSE_NOTE(1), "ERROR: cert= option must be set before key= is used.");
63 return;
0b0e0864 64 }
d1d72d43
AJ
65 KeyData &t = certs.back();
66 t.privateKeyFile = SBuf(token + 4);
0b0e0864 67 } else if (strncmp(token, "version=", 8) == 0) {
1cc44095 68 debugs(0, DBG_PARSE_NOTE(1), "UPGRADE WARNING: SSL version= is deprecated. Use options= to limit protocols instead.");
0b0e0864 69 sslVersion = xatoi(token + 8);
1cc44095
AJ
70 } else if (strncmp(token, "min-version=", 12) == 0) {
71 tlsMinVersion = SBuf(token + 12);
0b0e0864
AJ
72 } else if (strncmp(token, "options=", 8) == 0) {
73 sslOptions = SBuf(token + 8);
c62717bd 74 parsedOptions = parseOptions();
0b0e0864
AJ
75 } else if (strncmp(token, "cipher=", 7) == 0) {
76 sslCipher = SBuf(token + 7);
77 } else if (strncmp(token, "cafile=", 7) == 0) {
86a84cc0 78 caFiles.emplace_back(SBuf(token + 7));
0b0e0864
AJ
79 } else if (strncmp(token, "capath=", 7) == 0) {
80 caDir = SBuf(token + 7);
86a84cc0
AJ
81#if !USE_OPENSSL
82 debugs(3, DBG_PARSE_NOTE(1), "WARNING: capath= option requires --with-openssl.");
83#endif
0b0e0864
AJ
84 } else if (strncmp(token, "crlfile=", 8) == 0) {
85 crlFile = SBuf(token + 8);
6b19d1f9 86 loadCrlFile();
0b0e0864 87 } else if (strncmp(token, "flags=", 6) == 0) {
b24e9ae7 88 if (parsedFlags != 0) {
9a622f3e 89 debugs(3, DBG_PARSE_NOTE(1), "WARNING: Overwriting flags=" << sslFlags << " with " << SBuf(token + 6));
b24e9ae7 90 }
0b0e0864 91 sslFlags = SBuf(token + 6);
ec4defdb 92 parsedFlags = parseFlags();
435c72b0
AJ
93 } else if (strncmp(token, "default-ca=off", 14) == 0 || strncmp(token, "no-default-ca", 13) == 0) {
94 if (flags.tlsDefaultCa.configured() && flags.tlsDefaultCa)
95 fatalf("ERROR: previous default-ca settings conflict with %s", token);
96 flags.tlsDefaultCa.configure(false);
97 } else if (strncmp(token, "default-ca=on", 13) == 0 || strncmp(token, "default-ca", 10) == 0) {
98 if (flags.tlsDefaultCa.configured() && !flags.tlsDefaultCa)
99 fatalf("ERROR: previous default-ca settings conflict with %s", token);
100 flags.tlsDefaultCa.configure(true);
0b0e0864
AJ
101 } else if (strncmp(token, "domain=", 7) == 0) {
102 sslDomain = SBuf(token + 7);
b05d749d
AJ
103 } else if (strncmp(token, "no-npn", 6) == 0) {
104 flags.tlsNpn = false;
9a622f3e
AJ
105 } else {
106 debugs(3, DBG_CRITICAL, "ERROR: Unknown TLS option '" << token << "'");
d4ab7b63 107 return;
0b0e0864 108 }
d4ab7b63
AJ
109
110 encryptTransport = true;
0b0e0864
AJ
111}
112
8250ca31
AJ
113void
114Security::PeerOptions::dumpCfg(Packable *p, const char *pfx) const
115{
116 if (!encryptTransport) {
117 p->appendf(" %sdisable", pfx);
118 return; // no other settings are relevant
119 }
120
d1d72d43
AJ
121 for (auto &i : certs) {
122 if (!i.certFile.isEmpty())
123 p->appendf(" %scert=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(i.certFile));
8250ca31 124
d1d72d43
AJ
125 if (!i.privateKeyFile.isEmpty() && i.privateKeyFile != i.certFile)
126 p->appendf(" %skey=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(i.privateKeyFile));
127 }
8250ca31
AJ
128
129 if (!sslOptions.isEmpty())
130 p->appendf(" %soptions=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslOptions));
131
132 if (!sslCipher.isEmpty())
133 p->appendf(" %scipher=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslCipher));
134
86a84cc0
AJ
135 for (auto i : caFiles) {
136 p->appendf(" %scafile=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(i));
137 }
8250ca31
AJ
138
139 if (!caDir.isEmpty())
140 p->appendf(" %scapath=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(caDir));
141
142 if (!crlFile.isEmpty())
143 p->appendf(" %scrlfile=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(crlFile));
144
145 if (!sslFlags.isEmpty())
146 p->appendf(" %sflags=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslFlags));
0278bdcb 147
435c72b0
AJ
148 if (flags.tlsDefaultCa.configured()) {
149 // default ON for peers / upstream servers
150 // default OFF for listening ports
151 if (flags.tlsDefaultCa)
152 p->appendf(" %sdefault-ca", pfx);
153 else
154 p->appendf(" %sdefault-ca=off", pfx);
155 }
b05d749d
AJ
156
157 if (!flags.tlsNpn)
158 p->appendf(" %sno-npn", pfx);
8250ca31
AJ
159}
160
585c27eb
AJ
161void
162Security::PeerOptions::updateTlsVersionLimits()
9a2f63e7 163{
1cc44095
AJ
164 if (!tlsMinVersion.isEmpty()) {
165 ::Parser::Tokenizer tok(tlsMinVersion);
166 int64_t v = 0;
bd71ba99 167 if (tok.skip('1') && tok.skip('.') && tok.int64(v, 10, false, 1) && v <= 3) {
1cc44095 168 // only account for TLS here - SSL versions are handled by options= parameter
bd71ba99 169 // avoid affecting options= parameter in cachemgr config report
8250ca31 170#if SSL_OP_NO_TLSv1
1cc44095 171 if (v > 0)
8250ca31
AJ
172 parsedOptions |= SSL_OP_NO_TLSv1;
173#endif
174#if SSL_OP_NO_TLSv1_1
1cc44095 175 if (v > 1)
8250ca31
AJ
176 parsedOptions |= SSL_OP_NO_TLSv1_1;
177#endif
178#if SSL_OP_NO_TLSv1_2
1cc44095 179 if (v > 2)
8250ca31
AJ
180 parsedOptions |= SSL_OP_NO_TLSv1_2;
181#endif
1cc44095
AJ
182
183 } else {
184 debugs(0, DBG_PARSE_NOTE(1), "WARNING: Unknown TLS minimum version: " << tlsMinVersion);
185 }
186
187 } else if (sslVersion > 2) {
188 // backward compatibility hack for sslversion= configuration
189 // only use if tls-min-version=N.N is not present
8250ca31
AJ
190 // values 0-2 for auto and SSLv2 are not supported any longer.
191 // Do it this way so we DO cause changes to options= in cachemgr config report
1cc44095
AJ
192 const char *add = NULL;
193 switch (sslVersion) {
194 case 3:
195 add = "NO_TLSv1,NO_TLSv1_1,NO_TLSv1_2";
196 break;
197 case 4:
198 add = "NO_SSLv3,NO_TLSv1_1,NO_TLSv1_2";
199 break;
200 case 5:
201 add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_2";
202 break;
203 case 6:
204 add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_1";
205 break;
206 default: // nothing
207 break;
208 }
209 if (add) {
210 if (!sslOptions.isEmpty())
211 sslOptions.append(",",1);
212 sslOptions.append(add, strlen(add));
213 }
214 sslVersion = 0; // prevent sslOptions being repeatedly appended
215 }
585c27eb 216}
1cc44095 217
64769c79 218Security::ContextPointer
885f0ecf
AJ
219Security::PeerOptions::createBlankContext() const
220{
64769c79 221 Security::ContextPointer ctx;
885f0ecf 222#if USE_OPENSSL
0a28c16a
AJ
223 Ssl::Initialize();
224
885f0ecf 225#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
64769c79 226 SSL_CTX *t = SSL_CTX_new(TLS_client_method());
885f0ecf 227#else
64769c79 228 SSL_CTX *t = SSL_CTX_new(SSLv23_client_method());
885f0ecf
AJ
229#endif
230 if (!t) {
231 const auto x = ERR_error_string(ERR_get_error(), nullptr);
232 fatalf("Failed to allocate TLS client context: %s\n", x);
233 }
64769c79 234 ctx.resetWithoutLocking(t);
885f0ecf
AJ
235
236#elif USE_GNUTLS
237 // Initialize for X.509 certificate exchange
64769c79 238 gnutls_certificate_credentials_t t;
885f0ecf
AJ
239 if (const int x = gnutls_certificate_allocate_credentials(&t)) {
240 fatalf("Failed to allocate TLS client context: error=%d\n", x);
241 }
64769c79 242 ctx.resetWithoutLocking(t);
885f0ecf
AJ
243
244#else
c75aba02 245 debugs(83, 1, "WARNING: Failed to allocate TLS client context: No TLS library");
885f0ecf
AJ
246
247#endif
248
64769c79 249 return ctx;
885f0ecf
AJ
250}
251
96993ee0 252Security::ContextPtr
a465e144 253Security::PeerOptions::createClientContext(bool setOptions)
9a2f63e7 254{
585c27eb 255 updateTlsVersionLimits();
86a84cc0 256
64769c79 257 Security::ContextPointer t = createBlankContext();
c75aba02 258 if (t) {
9a2f63e7 259#if USE_OPENSSL
c75aba02
AJ
260 // XXX: temporary performance regression. c_str() data copies and prevents this being a const method
261 Ssl::InitClientContext(t, *this, (setOptions ? parsedOptions : 0), parsedFlags);
9a2f63e7 262#endif
b05d749d 263 updateContextNpn(t);
64769c79
AJ
264 updateContextCa(t.get());
265 updateContextCrl(t.get());
86a84cc0 266 }
6b19d1f9 267
64769c79 268 return t.release();
9a2f63e7 269}
1f1f29e8 270
6bd62757
AJ
271/// set of options we can parse and what they map to
272static struct ssl_option {
273 const char *name;
274 long value;
275
276} ssl_options[] = {
277
278#if SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
279 {
280 "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
281 },
282#endif
283#if SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
284 {
285 "SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
286 },
287#endif
288#if SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
289 {
290 "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
291 },
292#endif
293#if SSL_OP_SSLEAY_080_CLIENT_DH_BUG
294 {
295 "SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG
296 },
297#endif
298#if SSL_OP_TLS_D5_BUG
299 {
300 "TLS_D5_BUG", SSL_OP_TLS_D5_BUG
301 },
302#endif
303#if SSL_OP_TLS_BLOCK_PADDING_BUG
304 {
305 "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG
306 },
307#endif
308#if SSL_OP_TLS_ROLLBACK_BUG
309 {
310 "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG
311 },
312#endif
313#if SSL_OP_ALL
314 {
315 "ALL", (long)SSL_OP_ALL
316 },
317#endif
318#if SSL_OP_SINGLE_DH_USE
319 {
320 "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE
321 },
322#endif
323#if SSL_OP_EPHEMERAL_RSA
324 {
325 "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA
326 },
327#endif
328#if SSL_OP_PKCS1_CHECK_1
329 {
330 "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1
331 },
332#endif
333#if SSL_OP_PKCS1_CHECK_2
334 {
335 "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2
336 },
337#endif
338#if SSL_OP_NETSCAPE_CA_DN_BUG
339 {
340 "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG
341 },
342#endif
343#if SSL_OP_NON_EXPORT_FIRST
344 {
345 "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST
346 },
347#endif
348#if SSL_OP_CIPHER_SERVER_PREFERENCE
349 {
350 "CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE
351 },
352#endif
353#if SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
354 {
355 "NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
356 },
357#endif
358#if SSL_OP_NO_SSLv3
359 {
360 "NO_SSLv3", SSL_OP_NO_SSLv3
361 },
362#endif
363#if SSL_OP_NO_TLSv1
364 {
365 "NO_TLSv1", SSL_OP_NO_TLSv1
366 },
367#endif
368#if SSL_OP_NO_TLSv1_1
369 {
370 "NO_TLSv1_1", SSL_OP_NO_TLSv1_1
371 },
372#endif
373#if SSL_OP_NO_TLSv1_2
374 {
375 "NO_TLSv1_2", SSL_OP_NO_TLSv1_2
376 },
377#endif
378#if SSL_OP_NO_COMPRESSION
379 {
380 "No_Compression", SSL_OP_NO_COMPRESSION
381 },
382#endif
383#if SSL_OP_NO_TICKET
384 {
385 "NO_TICKET", SSL_OP_NO_TICKET
386 },
585c27eb
AJ
387#endif
388#if SSL_OP_SINGLE_ECDH_USE
389 {
390 "SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE
391 },
6bd62757
AJ
392#endif
393 {
394 "", 0
395 },
396 {
397 NULL, 0
398 }
399};
400
c62717bd
AJ
401/**
402 * Pre-parse TLS options= parameter to be applied when the TLS objects created.
403 * Options must not used in the case of peek or stare bump mode.
404 */
6bd62757 405long
c62717bd 406Security::PeerOptions::parseOptions()
6bd62757
AJ
407{
408 long op = 0;
c62717bd 409 ::Parser::Tokenizer tok(sslOptions);
6bd62757 410
c62717bd 411 do {
6bd62757
AJ
412 enum {
413 MODE_ADD, MODE_REMOVE
414 } mode;
415
c62717bd 416 if (tok.skip('-') || tok.skip('!'))
6bd62757 417 mode = MODE_REMOVE;
c62717bd
AJ
418 else {
419 (void)tok.skip('+'); // default action is add. ignore if missing operator
6bd62757 420 mode = MODE_ADD;
c62717bd 421 }
6bd62757 422
c62717bd
AJ
423 static const CharacterSet optChars = CharacterSet("TLS-option", "_") + CharacterSet::ALPHA + CharacterSet::DIGIT;
424 int64_t hex = 0;
425 SBuf option;
426 long value = 0;
427
144acb47
AJ
428 // Bug 4429: identify the full option name before determining text or numeric
429 if (tok.prefix(option, optChars)) {
6bd62757 430
c62717bd
AJ
431 // find the named option in our supported set
432 for (struct ssl_option *opttmp = ssl_options; opttmp->name; ++opttmp) {
433 if (option.cmp(opttmp->name) == 0) {
434 value = opttmp->value;
435 break;
436 }
6bd62757 437 }
144acb47
AJ
438
439 // Special case.. hex specification
440 ::Parser::Tokenizer tmp(option);
441 if (!value && tmp.int64(hex, 16, false) && tmp.atEnd()) {
442 value = hex;
443 }
6bd62757
AJ
444 }
445
40bc593b
AJ
446 if (value) {
447 switch (mode) {
448 case MODE_ADD:
449 op |= value;
450 break;
daf640c8 451 case MODE_REMOVE:
40bc593b
AJ
452 op &= ~value;
453 break;
454 }
455 } else {
456 debugs(83, DBG_PARSE_NOTE(1), "ERROR: Unknown TLS option " << option);
6bd62757
AJ
457 }
458
c62717bd
AJ
459 static const CharacterSet delims("TLS-option-delim",":,");
460 if (!tok.skipAll(delims) && !tok.atEnd()) {
461 fatalf("Unknown TLS option '" SQUIDSBUFPH "'", SQUIDSBUFPRINT(tok.remaining()));
462 }
6bd62757 463
c62717bd 464 } while (!tok.atEnd());
6bd62757
AJ
465
466#if SSL_OP_NO_SSLv2
467 // compliance with RFC 6176: Prohibiting Secure Sockets Layer (SSL) Version 2.0
468 op = op | SSL_OP_NO_SSLv2;
469#endif
470 return op;
471}
472
ec4defdb
AJ
473/**
474 * Parses the TLS flags squid.conf parameter
475 */
b24e9ae7 476long
ec4defdb 477Security::PeerOptions::parseFlags()
b24e9ae7 478{
ec4defdb 479 if (sslFlags.isEmpty())
b24e9ae7
AJ
480 return 0;
481
482 static struct {
483 SBuf label;
484 long mask;
485 } flagTokens[] = {
486 { SBuf("NO_DEFAULT_CA"), SSL_FLAG_NO_DEFAULT_CA },
487 { SBuf("DELAYED_AUTH"), SSL_FLAG_DELAYED_AUTH },
488 { SBuf("DONT_VERIFY_PEER"), SSL_FLAG_DONT_VERIFY_PEER },
489 { SBuf("DONT_VERIFY_DOMAIN"), SSL_FLAG_DONT_VERIFY_DOMAIN },
490 { SBuf("NO_SESSION_REUSE"), SSL_FLAG_NO_SESSION_REUSE },
491#if X509_V_FLAG_CRL_CHECK
492 { SBuf("VERIFY_CRL"), SSL_FLAG_VERIFY_CRL },
493 { SBuf("VERIFY_CRL_ALL"), SSL_FLAG_VERIFY_CRL_ALL },
494#endif
495 { SBuf(), 0 }
496 };
497
ec4defdb 498 ::Parser::Tokenizer tok(sslFlags);
b24e9ae7
AJ
499 static const CharacterSet delims("Flag-delimiter", ":,");
500
501 long fl = 0;
502 do {
503 long found = 0;
504 for (size_t i = 0; flagTokens[i].mask; ++i) {
3f6c1586 505 if (tok.skip(flagTokens[i].label)) {
b24e9ae7
AJ
506 found = flagTokens[i].mask;
507 break;
508 }
509 }
510 if (!found)
8250ca31 511 fatalf("Unknown TLS flag '" SQUIDSBUFPH "'", SQUIDSBUFPRINT(tok.remaining()));
8b253b83 512 if (found == SSL_FLAG_NO_DEFAULT_CA) {
435c72b0
AJ
513 if (flags.tlsDefaultCa.configured() && flags.tlsDefaultCa)
514 fatal("ERROR: previous default-ca settings conflict with sslflags=NO_DEFAULT_CA");
515 debugs(83, DBG_PARSE_NOTE(2), "WARNING: flags=NO_DEFAULT_CA is deprecated. Use tls-default-ca=off instead.");
516 flags.tlsDefaultCa.configure(false);
8b253b83
AJ
517 } else
518 fl |= found;
b24e9ae7
AJ
519 } while (tok.skipOne(delims));
520
521 return fl;
522}
523
6b19d1f9
AJ
524/// Load a CRLs list stored in the file whose /path/name is in crlFile
525/// replaces any CRL loaded previously
526void
527Security::PeerOptions::loadCrlFile()
528{
529 parsedCrl.clear();
530 if (crlFile.isEmpty())
531 return;
532
533#if USE_OPENSSL
534 BIO *in = BIO_new_file(crlFile.c_str(), "r");
535 if (!in) {
536 debugs(83, 2, "WARNING: Failed to open CRL file " << crlFile);
537 return;
538 }
539
540 while (X509_CRL *crl = PEM_read_bio_X509_CRL(in,NULL,NULL,NULL)) {
541 parsedCrl.emplace_back(Security::CrlPointer(crl));
542 }
543 BIO_free(in);
544#endif
545}
546
b05d749d
AJ
547#if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
548// Dummy next_proto_neg callback
549static int
550ssl_next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
551{
552 static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
553 (void)SSL_select_next_proto(out, outlen, in, inlen, supported_protos, sizeof(supported_protos));
554 return SSL_TLSEXT_ERR_OK;
555}
556#endif
557
558void
64769c79 559Security::PeerOptions::updateContextNpn(Security::ContextPointer &ctx)
b05d749d
AJ
560{
561 if (!flags.tlsNpn)
562 return;
563
564#if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
64769c79 565 SSL_CTX_set_next_proto_select_cb(ctx.get(), &ssl_next_proto_cb, nullptr);
b05d749d
AJ
566#endif
567
568 // NOTE: GnuTLS does not support the obsolete NPN extension.
569 // it does support ALPN per-session, not per-context.
570}
571
4f4d3a57
AJ
572static const char *
573loadSystemTrustedCa(Security::ContextPtr &ctx)
574{
575#if USE_OPENSSL
576 if (SSL_CTX_set_default_verify_paths(ctx) == 0)
03c428e9 577 return ERR_error_string(ERR_get_error(), nullptr);
4f4d3a57
AJ
578
579#elif USE_GNUTLS
580 auto x = gnutls_certificate_set_x509_system_trust(ctx);
581 if (x < 0)
582 return gnutls_strerror(x);
583
584#endif
585 return nullptr;
586}
587
86a84cc0 588void
64769c79 589Security::PeerOptions::updateContextCa(Security::ContextPtr ctx)
86a84cc0
AJ
590{
591 debugs(83, 8, "Setting CA certificate locations.");
123d5c2a
AJ
592#if USE_OPENSSL
593 const char *path = caDir.isEmpty() ? nullptr : caDir.c_str();
594#endif
86a84cc0
AJ
595 for (auto i : caFiles) {
596#if USE_OPENSSL
123d5c2a 597 if (!SSL_CTX_load_verify_locations(ctx, i.c_str(), path)) {
86a84cc0
AJ
598 const int ssl_error = ERR_get_error();
599 debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL));
600 }
601#elif USE_GNUTLS
602 if (gnutls_certificate_set_x509_trust_file(ctx, i.c_str(), GNUTLS_X509_FMT_PEM) < 0) {
603 debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location: " << i);
604 }
605#endif
606 }
607
b2cd014b 608 if (!flags.tlsDefaultCa)
86a84cc0
AJ
609 return;
610
4f4d3a57
AJ
611 if (const char *err = loadSystemTrustedCa(ctx)) {
612 debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default trusted CA : " << err);
86a84cc0 613 }
86a84cc0
AJ
614}
615
6b19d1f9 616void
64769c79 617Security::PeerOptions::updateContextCrl(Security::ContextPtr ctx)
6b19d1f9
AJ
618{
619#if USE_OPENSSL
620 bool verifyCrl = false;
621 X509_STORE *st = SSL_CTX_get_cert_store(ctx);
622 if (parsedCrl.size()) {
623 for (auto &i : parsedCrl) {
624 if (!X509_STORE_add_crl(st, i.get()))
625 debugs(83, 2, "WARNING: Failed to add CRL");
626 else
627 verifyCrl = true;
628 }
629 }
630
631#if X509_V_FLAG_CRL_CHECK
632 if ((parsedFlags & SSL_FLAG_VERIFY_CRL_ALL))
633 X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
634 else if (verifyCrl || (parsedFlags & SSL_FLAG_VERIFY_CRL))
635 X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK);
636#endif
637
638#endif /* USE_OPENSSL */
639}
640
1f1f29e8
AJ
641void
642parse_securePeerOptions(Security::PeerOptions *opt)
643{
644 while(const char *token = ConfigParser::NextToken())
645 opt->parse(token);
646}
647