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