]> git.ipfire.org Git - thirdparty/squid.git/blame - src/security/PeerOptions.cc
Fix uninitializd PeerOptions::parsedFlags
[thirdparty/squid.git] / src / security / PeerOptions.cc
CommitLineData
9a2f63e7 1/*
be75380c 2 * Copyright (C) 1996-2015 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"
0b0e0864 10#include "Debug.h"
6bd62757 11#include "fatal.h"
0b0e0864 12#include "globals.h"
1cc44095 13#include "parser/Tokenizer.h"
0b0e0864 14#include "Parsing.h"
b24e9ae7 15#include "parser/Tokenizer.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
AJ
24Security::PeerOptions::PeerOptions(const Security::PeerOptions &p) :
25 certFile(p.certFile),
26 privateKeyFile(p.privateKeyFile),
27 sslOptions(p.sslOptions),
28 caFile(p.caFile),
29 caDir(p.caDir),
30 crlFile(p.crlFile),
31 sslCipher(p.sslCipher),
32 sslFlags(p.sslFlags),
33 sslDomain(p.sslDomain),
34 parsedOptions(p.parsedOptions),
35 parsedFlags(p.parsedFlags),
36 sslVersion(p.sslVersion),
37 encryptTransport(p.encryptTransport)
38{
39}
40
0b0e0864
AJ
41void
42Security::PeerOptions::parse(const char *token)
43{
44 if (strncmp(token, "cert=", 5) == 0) {
45 certFile = SBuf(token + 5);
1f1f29e8
AJ
46 if (privateKeyFile.isEmpty())
47 privateKeyFile = certFile;
0b0e0864
AJ
48 } else if (strncmp(token, "key=", 4) == 0) {
49 privateKeyFile = SBuf(token + 4);
50 if (certFile.isEmpty()) {
9a622f3e 51 debugs(3, DBG_PARSE_NOTE(1), "WARNING: cert= option needs to be set before key= is used.");
0b0e0864
AJ
52 certFile = privateKeyFile;
53 }
54 } else if (strncmp(token, "version=", 8) == 0) {
1cc44095 55 debugs(0, DBG_PARSE_NOTE(1), "UPGRADE WARNING: SSL version= is deprecated. Use options= to limit protocols instead.");
0b0e0864 56 sslVersion = xatoi(token + 8);
1cc44095
AJ
57 } else if (strncmp(token, "min-version=", 12) == 0) {
58 tlsMinVersion = SBuf(token + 12);
0b0e0864
AJ
59 } else if (strncmp(token, "options=", 8) == 0) {
60 sslOptions = SBuf(token + 8);
36092741
AJ
61#if USE_OPENSSL
62 // Pre-parse SSL client options to be applied when the client SSL objects created.
63 // Options must not used in the case of peek or stare bump mode.
64 // XXX: performance regression. c_str() can reallocate
6bd62757 65 parsedOptions = Security::ParseOptions(sslOptions.c_str());
36092741 66#endif
0b0e0864
AJ
67 } else if (strncmp(token, "cipher=", 7) == 0) {
68 sslCipher = SBuf(token + 7);
69 } else if (strncmp(token, "cafile=", 7) == 0) {
70 caFile = SBuf(token + 7);
71 } else if (strncmp(token, "capath=", 7) == 0) {
72 caDir = SBuf(token + 7);
73 } else if (strncmp(token, "crlfile=", 8) == 0) {
74 crlFile = SBuf(token + 8);
75 } else if (strncmp(token, "flags=", 6) == 0) {
b24e9ae7 76 if (parsedFlags != 0) {
9a622f3e 77 debugs(3, DBG_PARSE_NOTE(1), "WARNING: Overwriting flags=" << sslFlags << " with " << SBuf(token + 6));
b24e9ae7 78 }
0b0e0864 79 sslFlags = SBuf(token + 6);
b24e9ae7 80 parsedFlags = Security::ParseFlags(sslFlags);
0b0e0864
AJ
81 } else if (strncmp(token, "domain=", 7) == 0) {
82 sslDomain = SBuf(token + 7);
9a622f3e
AJ
83 } else {
84 debugs(3, DBG_CRITICAL, "ERROR: Unknown TLS option '" << token << "'");
0b0e0864
AJ
85 }
86}
87
585c27eb
AJ
88void
89Security::PeerOptions::updateTlsVersionLimits()
9a2f63e7 90{
1cc44095
AJ
91 if (!tlsMinVersion.isEmpty()) {
92 ::Parser::Tokenizer tok(tlsMinVersion);
93 int64_t v = 0;
94 if (tok.skip('1') && tok.skip('.') && tok.int64(v, 10, false, 1) && v <= 2) {
95 // only account for TLS here - SSL versions are handled by options= parameter
96 if (v > 0)
97 sslOptions.append(",NO_TLSv1",9);
98 if (v > 1)
99 sslOptions.append(",NO_TLSv1_1",11);
100 if (v > 2)
101 sslOptions.append(",NO_TLSv1_2",11);
102
103 } else {
104 debugs(0, DBG_PARSE_NOTE(1), "WARNING: Unknown TLS minimum version: " << tlsMinVersion);
105 }
106
107 } else if (sslVersion > 2) {
108 // backward compatibility hack for sslversion= configuration
109 // only use if tls-min-version=N.N is not present
110
111 const char *add = NULL;
112 switch (sslVersion) {
113 case 3:
114 add = "NO_TLSv1,NO_TLSv1_1,NO_TLSv1_2";
115 break;
116 case 4:
117 add = "NO_SSLv3,NO_TLSv1_1,NO_TLSv1_2";
118 break;
119 case 5:
120 add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_2";
121 break;
122 case 6:
123 add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_1";
124 break;
125 default: // nothing
126 break;
127 }
128 if (add) {
129 if (!sslOptions.isEmpty())
130 sslOptions.append(",",1);
131 sslOptions.append(add, strlen(add));
132 }
133 sslVersion = 0; // prevent sslOptions being repeatedly appended
134 }
585c27eb 135}
1cc44095 136
9a2f63e7
AJ
137// XXX: make a GnuTLS variant
138Security::ContextPointer
a465e144 139Security::PeerOptions::createClientContext(bool setOptions)
9a2f63e7
AJ
140{
141 Security::ContextPointer t = NULL;
142
585c27eb 143 updateTlsVersionLimits();
9a2f63e7 144#if USE_OPENSSL
1f1f29e8 145 // XXX: temporary performance regression. c_str() data copies and prevents this being a const method
1cc44095 146 t = sslCreateClientContext(certFile.c_str(), privateKeyFile.c_str(), sslCipher.c_str(),
585c27eb 147 (setOptions ? parsedOptions : 0), parsedFlags,
1cc44095 148 caFile.c_str(), caDir.c_str(), crlFile.c_str());
9a2f63e7 149#endif
36092741 150
9a2f63e7
AJ
151 return t;
152}
1f1f29e8 153
6bd62757
AJ
154/// set of options we can parse and what they map to
155static struct ssl_option {
156 const char *name;
157 long value;
158
159} ssl_options[] = {
160
161#if SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
162 {
163 "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
164 },
165#endif
166#if SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
167 {
168 "SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
169 },
170#endif
171#if SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
172 {
173 "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
174 },
175#endif
176#if SSL_OP_SSLEAY_080_CLIENT_DH_BUG
177 {
178 "SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG
179 },
180#endif
181#if SSL_OP_TLS_D5_BUG
182 {
183 "TLS_D5_BUG", SSL_OP_TLS_D5_BUG
184 },
185#endif
186#if SSL_OP_TLS_BLOCK_PADDING_BUG
187 {
188 "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG
189 },
190#endif
191#if SSL_OP_TLS_ROLLBACK_BUG
192 {
193 "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG
194 },
195#endif
196#if SSL_OP_ALL
197 {
198 "ALL", (long)SSL_OP_ALL
199 },
200#endif
201#if SSL_OP_SINGLE_DH_USE
202 {
203 "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE
204 },
205#endif
206#if SSL_OP_EPHEMERAL_RSA
207 {
208 "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA
209 },
210#endif
211#if SSL_OP_PKCS1_CHECK_1
212 {
213 "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1
214 },
215#endif
216#if SSL_OP_PKCS1_CHECK_2
217 {
218 "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2
219 },
220#endif
221#if SSL_OP_NETSCAPE_CA_DN_BUG
222 {
223 "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG
224 },
225#endif
226#if SSL_OP_NON_EXPORT_FIRST
227 {
228 "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST
229 },
230#endif
231#if SSL_OP_CIPHER_SERVER_PREFERENCE
232 {
233 "CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE
234 },
235#endif
236#if SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
237 {
238 "NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
239 },
240#endif
241#if SSL_OP_NO_SSLv3
242 {
243 "NO_SSLv3", SSL_OP_NO_SSLv3
244 },
245#endif
246#if SSL_OP_NO_TLSv1
247 {
248 "NO_TLSv1", SSL_OP_NO_TLSv1
249 },
250#endif
251#if SSL_OP_NO_TLSv1_1
252 {
253 "NO_TLSv1_1", SSL_OP_NO_TLSv1_1
254 },
255#endif
256#if SSL_OP_NO_TLSv1_2
257 {
258 "NO_TLSv1_2", SSL_OP_NO_TLSv1_2
259 },
260#endif
261#if SSL_OP_NO_COMPRESSION
262 {
263 "No_Compression", SSL_OP_NO_COMPRESSION
264 },
265#endif
266#if SSL_OP_NO_TICKET
267 {
268 "NO_TICKET", SSL_OP_NO_TICKET
269 },
585c27eb
AJ
270#endif
271#if SSL_OP_SINGLE_ECDH_USE
272 {
273 "SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE
274 },
6bd62757
AJ
275#endif
276 {
277 "", 0
278 },
279 {
280 NULL, 0
281 }
282};
283
284long
285Security::ParseOptions(const char *options)
286{
287 long op = 0;
288 char *tmp;
289 char *option;
290
291 if (options) {
292
293 tmp = xstrdup(options);
294 option = strtok(tmp, ":,");
295
296 while (option) {
297
298 enum {
299 MODE_ADD, MODE_REMOVE
300 } mode;
301
302 switch (*option) {
303
304 case '!':
305
306 case '-':
307 mode = MODE_REMOVE;
308 ++option;
309 break;
310
311 case '+':
312 mode = MODE_ADD;
313 ++option;
314 break;
315
316 default:
317 mode = MODE_ADD;
318 break;
319 }
320
321 struct ssl_option *opt = NULL;
322 for (struct ssl_option *opttmp = ssl_options; opttmp->name; ++opttmp) {
323 if (strcmp(opttmp->name, option) == 0) {
324 opt = opttmp;
325 break;
326 }
327 }
328
329 long value = 0;
330 if (opt)
331 value = opt->value;
332 else if (strncmp(option, "0x", 2) == 0) {
333 /* Special case.. hex specification */
334 value = strtol(option + 2, NULL, 16);
335 } else {
336 fatalf("Unknown SSL option '%s'", option);
337 value = 0; /* Keep GCC happy */
338 }
339
340 switch (mode) {
341
342 case MODE_ADD:
343 op |= value;
344 break;
345
346 case MODE_REMOVE:
347 op &= ~value;
348 break;
349 }
350
351 option = strtok(NULL, ":,");
352 }
353
354 safe_free(tmp);
355 }
356
357#if SSL_OP_NO_SSLv2
358 // compliance with RFC 6176: Prohibiting Secure Sockets Layer (SSL) Version 2.0
359 op = op | SSL_OP_NO_SSLv2;
360#endif
361 return op;
362}
363
b24e9ae7
AJ
364long
365Security::ParseFlags(const SBuf &flags)
366{
367 if (flags.isEmpty())
368 return 0;
369
370 static struct {
371 SBuf label;
372 long mask;
373 } flagTokens[] = {
374 { SBuf("NO_DEFAULT_CA"), SSL_FLAG_NO_DEFAULT_CA },
375 { SBuf("DELAYED_AUTH"), SSL_FLAG_DELAYED_AUTH },
376 { SBuf("DONT_VERIFY_PEER"), SSL_FLAG_DONT_VERIFY_PEER },
377 { SBuf("DONT_VERIFY_DOMAIN"), SSL_FLAG_DONT_VERIFY_DOMAIN },
378 { SBuf("NO_SESSION_REUSE"), SSL_FLAG_NO_SESSION_REUSE },
379#if X509_V_FLAG_CRL_CHECK
380 { SBuf("VERIFY_CRL"), SSL_FLAG_VERIFY_CRL },
381 { SBuf("VERIFY_CRL_ALL"), SSL_FLAG_VERIFY_CRL_ALL },
382#endif
383 { SBuf(), 0 }
384 };
385
386 ::Parser::Tokenizer tok(flags);
387 static const CharacterSet delims("Flag-delimiter", ":,");
388
389 long fl = 0;
390 do {
391 long found = 0;
392 for (size_t i = 0; flagTokens[i].mask; ++i) {
393 if (tok.skip(flagTokens[i].label) == 0) {
394 found = flagTokens[i].mask;
395 break;
396 }
397 }
398 if (!found)
399 fatalf("Unknown SSL flag '" SQUIDSBUFPH "'", SQUIDSBUFPRINT(tok.remaining()));
400 fl |= found;
401 } while (tok.skipOne(delims));
402
403 return fl;
404}
405
1f1f29e8
AJ
406void
407parse_securePeerOptions(Security::PeerOptions *opt)
408{
409 while(const char *token = ConfigParser::NextToken())
410 opt->parse(token);
411}
412