From: Amos Jeffries Date: Sun, 28 Jun 2015 15:02:53 +0000 (-0700) Subject: Merged from trunk rev.14126 X-Git-Tag: merge-candidate-3-v1~38^2~21^2~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=585c27ebf5f73381e605273c3b22a232f2f8f7f8;p=thirdparty%2Fsquid.git Merged from trunk rev.14126 --- 585c27ebf5f73381e605273c3b22a232f2f8f7f8 diff --cc src/Makefile.am index 4f2ee10fd1,ecc95486a9..12dde6ec67 --- a/src/Makefile.am +++ b/src/Makefile.am @@@ -611,7 -607,7 +607,6 @@@ squid_LDADD = http/libsquid-http.la \ parser/libsquid-parser.la \ dns/libdns.la \ -- security/libsecurity.la \ base/libbase.la \ libsquid.la \ ip/libip.la \ @@@ -620,6 -616,6 +615,7 @@@ ipc/libipc.la \ mgr/libmgr.la \ anyp/libanyp.la \ ++ security/libsecurity.la \ comm/libcomm.la \ eui/libeui.la \ icmp/libicmp.la icmp/libicmp-core.la \ @@@ -1254,9 -1247,7 +1248,8 @@@ tests_testACLMaxUserIP_SOURCES= SquidList.h \ SquidList.cc \ mem_node.cc \ - Packer.cc \ Parsing.cc \ + tests/stub_libsecurity.cc \ SquidMath.cc \ StatCounters.cc \ StatCounters.h \ diff --cc src/SquidConfig.h index 3402233961,f4c5a9777b..22c9d3dd4e --- a/src/SquidConfig.h +++ b/src/SquidConfig.h @@@ -15,10 -15,8 +15,9 @@@ #include "DelayConfig.h" #include "helper/ChildConfig.h" #include "HttpHeaderTools.h" - #include "icmp/IcmpConfig.h" #include "ip/Address.h" #include "Notes.h" +#include "security/forward.h" #include "YesNoNone.h" #if USE_OPENSSL diff --cc src/adaptation/icap/ServiceRep.cc index 0c8053e9da,b7f5ea6acd..1c5b608899 --- a/src/adaptation/icap/ServiceRep.cc +++ b/src/adaptation/icap/ServiceRep.cc @@@ -68,6 -79,14 +79,14 @@@ Adaptation::Icap::ServiceRep::finalize( } } + if (cfg().protocol.caseCmp("icaps") == 0) + writeableCfg().secure.encryptTransport = true; + + if (cfg().secure.encryptTransport) { + debugs(3, DBG_IMPORTANT, "Initializing service " << cfg().resource << " SSL context"); - sslContext = writeableCfg().secure.createContext(true); ++ sslContext = writeableCfg().secure.createClientContext(true); + } + theSessionFailures.configure(TheConfig.oldest_service_failure > 0 ? TheConfig.oldest_service_failure : -1); } diff --cc src/anyp/PortCfg.cc index a4facffded,26a10e3f2f..c3ea4e263f --- a/src/anyp/PortCfg.cc +++ b/src/anyp/PortCfg.cc @@@ -44,9 -44,18 +44,10 @@@ AnyP::PortCfg::PortCfg() disable_pmtu_discovery(0), listenConn() #if USE_OPENSSL - ,cert(NULL), - key(NULL), - version(0), - cipher(NULL), - options(NULL), + , clientca(NULL), - cafile(NULL), - capath(NULL), - crlfile(NULL), dhfile(NULL), + tls_dh(NULL), - sslflags(NULL), sslContextSessionId(NULL), generateHostCertificates(false), dynamicCertMemCacheSize(std::numeric_limits::max()), @@@ -59,7 -68,10 +60,8 @@@ clientVerifyCrls(), clientCA(), dhParams(), + eecdhCurve(NULL), - contextMethod(), - sslContextFlags(0), - sslOptions(0) + contextMethod() #endif { memset(&tcp_keepalive, 0, sizeof(tcp_keepalive)); @@@ -76,9 -88,19 +78,11 @@@ AnyP::PortCfg::~PortCfg( safe_free(defaultsite); #if USE_OPENSSL - safe_free(cert); - safe_free(key); - safe_free(cipher); - safe_free(options); safe_free(clientca); - safe_free(cafile); - safe_free(capath); - safe_free(crlfile); safe_free(dhfile); + safe_free(tls_dh); - safe_free(sslflags); safe_free(sslContextSessionId); + safe_free(eecdhCurve); #endif } @@@ -101,13 -123,31 +105,15 @@@ AnyP::PortCfg::clone() cons b->ftp_track_dirs = ftp_track_dirs; b->disable_pmtu_discovery = disable_pmtu_discovery; b->tcp_keepalive = tcp_keepalive; + b->secure = secure; #if USE_OPENSSL - if (cert) - b->cert = xstrdup(cert); - if (key) - b->key = xstrdup(key); - b->version = version; - if (cipher) - b->cipher = xstrdup(cipher); - if (options) - b->options = xstrdup(options); if (clientca) b->clientca = xstrdup(clientca); - if (cafile) - b->cafile = xstrdup(cafile); - if (capath) - b->capath = xstrdup(capath); - if (crlfile) - b->crlfile = xstrdup(crlfile); if (dhfile) b->dhfile = xstrdup(dhfile); + if (tls_dh) + b->tls_dh = xstrdup(tls_dh); - if (sslflags) - b->sslflags = xstrdup(sslflags); if (sslContextSessionId) b->sslContextSessionId = xstrdup(sslContextSessionId); @@@ -155,13 -195,67 +161,31 @@@ AnyP::PortCfg::configureSslServerContex } } - contextMethod = Ssl::contextMethod(secure.sslVersion); - if (!contextMethod) - fatalf("Unable to compute context method to use"); - // backward compatibility hack for sslversion= configuration - if (version > 2) { - const char *add = NULL; - switch (version) { - case 3: - add = "NO_TLSv1,NO_TLSv1_1,NO_TLSv1_2"; - break; - case 4: - add = "NO_SSLv3,NO_TLSv1_1,NO_TLSv1_2"; - break; - case 5: - add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_2"; - break; - case 6: - add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_1"; - break; - default: // nothing - break; - } - if (add) { - SBuf tmpOpts; - if (options) { - tmpOpts.append(options, strlen(options)); - tmpOpts.append(",",1); - } - tmpOpts.append(add, strlen(add)); - xfree(options); - options = xstrdup(tmpOpts.c_str()); - } - version = 0; // prevent options being repeatedly appended - } - ++ secure.updateTlsVersionLimits(); + #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + contextMethod = TLS_server_method(); + #else + contextMethod = SSLv23_server_method(); + #endif - if (dhfile) - dhParams.reset(Ssl::readDHParams(dhfile)); + const char *dhParamsFile = dhfile; // backward compatibility for dhparams= configuration + safe_free(eecdhCurve); // clear any previous EECDH configuration + if (tls_dh && *tls_dh) { + eecdhCurve = xstrdup(tls_dh); + char *p = strchr(eecdhCurve, ':'); + if (p) { // tls-dh=eecdhCurve:dhParamsFile + *p = '\0'; + dhParamsFile = p+1; + } else { // tls-dh=dhParamsFile + dhParamsFile = tls_dh; + // a NULL eecdhCurve means "do not use EECDH" + safe_free(eecdhCurve); + } + } + + if (dhParamsFile && *dhParamsFile) + dhParams.reset(Ssl::readDHParams(dhParamsFile)); - if (sslflags) - sslContextFlags = Ssl::parse_flags(sslflags); - - sslOptions = Ssl::parse_options(options); - staticSslContext.reset(sslCreateServerContext(*this)); if (!staticSslContext) { diff --cc src/anyp/PortCfg.h index a2b3def950,66670ebb43..7886f4748c --- a/src/anyp/PortCfg.h +++ b/src/anyp/PortCfg.h @@@ -69,12 -67,19 +69,13 @@@ public */ Comm::ConnectionPointer listenConn; + /// TLS configuration options for this listening port + Security::PeerOptions secure; + #if USE_OPENSSL - char *cert; - char *key; - int version; - char *cipher; - char *options; char *clientca; - char *cafile; - char *capath; - char *crlfile; char *dhfile; + char *tls_dh; - char *sslflags; char *sslContextSessionId; ///< "session id context" for staticSslContext bool generateHostCertificates; ///< dynamically make host cert for sslBump size_t dynamicCertMemCacheSize; ///< max size of generated certificates memory cache @@@ -89,7 -94,10 +90,8 @@@ Ssl::X509_CRL_STACK_Pointer clientVerifyCrls; ///< additional CRL lists to use when verifying the client certificate Ssl::X509_NAME_STACK_Pointer clientCA; ///< CA certificates to use when verifying client certificates Ssl::DH_Pointer dhParams; ///< DH parameters for temporary/ephemeral DH key exchanges + char *eecdhCurve; ///< Elliptic curve for ephemeral EC-based DH key exchanges Ssl::ContextMethod contextMethod; ///< The context method (SSL_METHOD) to use when creating certificates - long sslContextFlags; ///< flags modifying the use of SSL - long sslOptions; ///< SSL engine options #endif }; diff --cc src/cache_cf.cc index 485fb5f1b0,5c816bb5c3..444c711467 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@@ -3575,31 -3568,46 +3568,36 @@@ parse_port_option(AnyP::PortCfgPointer } else if (strcmp(token, "ssl-bump") == 0) { s->flags.tunnelSslBumping = true; } else if (strncmp(token, "cert=", 5) == 0) { - safe_free(s->cert); - s->cert = xstrdup(token + 5); + s->secure.parse(token); } else if (strncmp(token, "key=", 4) == 0) { - safe_free(s->key); - s->key = xstrdup(token + 4); + s->secure.parse(token); } else if (strncmp(token, "version=", 8) == 0) { + debugs(3, DBG_PARSE_NOTE(1), "UPGRADE WARNING: '" << token << "' is deprecated " << + "in " << cfg_directive << ". Use 'options=' instead."); - s->version = xatoi(token + 8); - if (s->version < 1 || s->version > 6) - self_destruct(); + s->secure.parse(token); - if (s->secure.sslVersion < 1 || s->secure.sslVersion > 4) - self_destruct(); } else if (strncmp(token, "options=", 8) == 0) { - safe_free(s->options); - s->options = xstrdup(token + 8); + s->secure.parse(token); } else if (strncmp(token, "cipher=", 7) == 0) { - safe_free(s->cipher); - s->cipher = xstrdup(token + 7); + s->secure.parse(token); } else if (strncmp(token, "clientca=", 9) == 0) { safe_free(s->clientca); s->clientca = xstrdup(token + 9); } else if (strncmp(token, "cafile=", 7) == 0) { - safe_free(s->cafile); - s->cafile = xstrdup(token + 7); + s->secure.parse(token); } else if (strncmp(token, "capath=", 7) == 0) { - safe_free(s->capath); - s->capath = xstrdup(token + 7); + s->secure.parse(token); } else if (strncmp(token, "crlfile=", 8) == 0) { - safe_free(s->crlfile); - s->crlfile = xstrdup(token + 8); + s->secure.parse(token); } else if (strncmp(token, "dhparams=", 9) == 0) { + debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: '" << token << "' is deprecated " << + "in " << cfg_directive << ". Use 'tls-dh=' instead."); safe_free(s->dhfile); s->dhfile = xstrdup(token + 9); + } else if (strncmp(token, "tls-dh=", 7) == 0) { + safe_free(s->tls_dh); + s->tls_dh = xstrdup(token + 7); } else if (strncmp(token, "sslflags=", 9) == 0) { - safe_free(s->sslflags); - s->sslflags = xstrdup(token + 9); + s->secure.parse(token+3); } else if (strncmp(token, "sslcontext=", 11) == 0) { safe_free(s->sslContextSessionId); s->sslContextSessionId = xstrdup(token + 11); @@@ -3794,36 -3800,37 +3792,36 @@@ dump_generic_port(StoreEntry * e, cons #if USE_OPENSSL if (s->flags.tunnelSslBumping) storeAppendPrintf(e, " ssl-bump"); +#endif - if (s->cert) - storeAppendPrintf(e, " cert=%s", s->cert); + if (!s->secure.certFile.isEmpty()) + storeAppendPrintf(e, " tls-cert=" SQUIDSBUFPH, SQUIDSBUFPRINT(s->secure.certFile)); - if (s->key) - storeAppendPrintf(e, " key=%s", s->key); + if (!s->secure.privateKeyFile.isEmpty() && s->secure.privateKeyFile != s->secure.certFile) + storeAppendPrintf(e, " tls-key=" SQUIDSBUFPH, SQUIDSBUFPRINT(s->secure.privateKeyFile)); - if (s->secure.sslVersion) - storeAppendPrintf(e, " tls-version=%d", s->secure.sslVersion); - - if (s->options) - storeAppendPrintf(e, " options=%s", s->options); + if (!s->secure.sslOptions.isEmpty()) + storeAppendPrintf(e, " tls-options=" SQUIDSBUFPH, SQUIDSBUFPRINT(s->secure.sslOptions)); - if (s->cipher) - storeAppendPrintf(e, " cipher=%s", s->cipher); + if (!s->secure.sslCipher.isEmpty()) + storeAppendPrintf(e, " tls-cipher=" SQUIDSBUFPH, SQUIDSBUFPRINT(s->secure.sslCipher)); - if (s->cafile) - storeAppendPrintf(e, " cafile=%s", s->cafile); + if (!s->secure.caFile.isEmpty()) + storeAppendPrintf(e, " tls-cafile=" SQUIDSBUFPH, SQUIDSBUFPRINT(s->secure.caFile)); - if (s->capath) - storeAppendPrintf(e, " capath=%s", s->capath); + if (!s->secure.caDir.isEmpty()) + storeAppendPrintf(e, " tls-capath=" SQUIDSBUFPH, SQUIDSBUFPRINT(s->secure.caDir)); - if (s->crlfile) - storeAppendPrintf(e, " crlfile=%s", s->crlfile); + if (!s->secure.crlFile.isEmpty()) + storeAppendPrintf(e, " tls-crlfile=" SQUIDSBUFPH, SQUIDSBUFPRINT(s->secure.crlFile)); +#if USE_OPENSSL if (s->dhfile) storeAppendPrintf(e, " dhparams=%s", s->dhfile); + if (s->tls_dh) + storeAppendPrintf(e, " tls-dh=%s", s->tls_dh); + - if (s->sslflags) - storeAppendPrintf(e, " sslflags=%s", s->sslflags); - if (s->sslContextSessionId) storeAppendPrintf(e, " sslcontext=%s", s->sslContextSessionId); diff --cc src/security/PeerOptions.cc index 9aa8706fb0,577053755e..94e32741ca --- a/src/security/PeerOptions.cc +++ b/src/security/PeerOptions.cc @@@ -8,10 -8,9 +8,11 @@@ #include "squid.h" #include "Debug.h" +#include "fatal.h" #include "globals.h" + #include "parser/Tokenizer.h" #include "Parsing.h" +#include "parser/Tokenizer.h" #include "security/PeerOptions.h" #if USE_OPENSSL @@@ -81,269 -60,67 +85,324 @@@ Security::PeerOptions::parse(const cha } } -// XXX: make a GnuTLS variant -Security::ContextPointer -Security::PeerOptions::createContext(bool setOptions) ++void ++Security::PeerOptions::updateTlsVersionLimits() + { - Security::ContextPointer t = NULL; - + if (!tlsMinVersion.isEmpty()) { + ::Parser::Tokenizer tok(tlsMinVersion); + int64_t v = 0; + if (tok.skip('1') && tok.skip('.') && tok.int64(v, 10, false, 1) && v <= 2) { + // only account for TLS here - SSL versions are handled by options= parameter + if (v > 0) + sslOptions.append(",NO_TLSv1",9); + if (v > 1) + sslOptions.append(",NO_TLSv1_1",11); + if (v > 2) + sslOptions.append(",NO_TLSv1_2",11); + + } else { + debugs(0, DBG_PARSE_NOTE(1), "WARNING: Unknown TLS minimum version: " << tlsMinVersion); + } + + } else if (sslVersion > 2) { + // backward compatibility hack for sslversion= configuration + // only use if tls-min-version=N.N is not present + + const char *add = NULL; + switch (sslVersion) { + case 3: + add = "NO_TLSv1,NO_TLSv1_1,NO_TLSv1_2"; + break; + case 4: + add = "NO_SSLv3,NO_TLSv1_1,NO_TLSv1_2"; + break; + case 5: + add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_2"; + break; + case 6: + add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_1"; + break; + default: // nothing + break; + } + if (add) { + if (!sslOptions.isEmpty()) + sslOptions.append(",",1); + sslOptions.append(add, strlen(add)); + } + sslVersion = 0; // prevent sslOptions being repeatedly appended + } ++} + +// XXX: make a GnuTLS variant +Security::ContextPointer +Security::PeerOptions::createClientContext(bool setOptions) +{ + Security::ContextPointer t = NULL; + ++ updateTlsVersionLimits(); #if USE_OPENSSL // XXX: temporary performance regression. c_str() data copies and prevents this being a const method - t = sslCreateClientContext(certFile.c_str(), privateKeyFile.c_str(), sslVersion, sslCipher.c_str(), - (setOptions ? parsedOptions : 0), parsedFlags, caFile.c_str(), caDir.c_str(), crlFile.c_str()); - + t = sslCreateClientContext(certFile.c_str(), privateKeyFile.c_str(), sslCipher.c_str(), - (setOptions ? sslOptions.c_str() : NULL), sslFlags.c_str(), ++ (setOptions ? parsedOptions : 0), parsedFlags, + caFile.c_str(), caDir.c_str(), crlFile.c_str()); #endif return t; } +/// set of options we can parse and what they map to +static struct ssl_option { + const char *name; + long value; + +} ssl_options[] = { + +#if SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG + { + "NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG + }, +#endif +#if SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG + { + "SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG + }, +#endif +#if SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER + { + "MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER + }, +#endif +#if SSL_OP_SSLEAY_080_CLIENT_DH_BUG + { + "SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG + }, +#endif +#if SSL_OP_TLS_D5_BUG + { + "TLS_D5_BUG", SSL_OP_TLS_D5_BUG + }, +#endif +#if SSL_OP_TLS_BLOCK_PADDING_BUG + { + "TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG + }, +#endif +#if SSL_OP_TLS_ROLLBACK_BUG + { + "TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG + }, +#endif +#if SSL_OP_ALL + { + "ALL", (long)SSL_OP_ALL + }, +#endif +#if SSL_OP_SINGLE_DH_USE + { + "SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE + }, +#endif +#if SSL_OP_EPHEMERAL_RSA + { + "EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA + }, +#endif +#if SSL_OP_PKCS1_CHECK_1 + { + "PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1 + }, +#endif +#if SSL_OP_PKCS1_CHECK_2 + { + "PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2 + }, +#endif +#if SSL_OP_NETSCAPE_CA_DN_BUG + { + "NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG + }, +#endif +#if SSL_OP_NON_EXPORT_FIRST + { + "NON_EXPORT_FIRST", SSL_OP_NON_EXPORT_FIRST + }, +#endif +#if SSL_OP_CIPHER_SERVER_PREFERENCE + { + "CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE + }, +#endif +#if SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG + { + "NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG + }, +#endif +#if SSL_OP_NO_SSLv3 + { + "NO_SSLv3", SSL_OP_NO_SSLv3 + }, +#endif +#if SSL_OP_NO_TLSv1 + { + "NO_TLSv1", SSL_OP_NO_TLSv1 + }, +#endif +#if SSL_OP_NO_TLSv1_1 + { + "NO_TLSv1_1", SSL_OP_NO_TLSv1_1 + }, +#endif +#if SSL_OP_NO_TLSv1_2 + { + "NO_TLSv1_2", SSL_OP_NO_TLSv1_2 + }, +#endif +#if SSL_OP_NO_COMPRESSION + { + "No_Compression", SSL_OP_NO_COMPRESSION + }, +#endif +#if SSL_OP_NO_TICKET + { + "NO_TICKET", SSL_OP_NO_TICKET + }, ++#endif ++#if SSL_OP_SINGLE_ECDH_USE ++ { ++ "SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE ++ }, +#endif + { + "", 0 + }, + { + NULL, 0 + } +}; + +long +Security::ParseOptions(const char *options) +{ + long op = 0; + char *tmp; + char *option; + + if (options) { + + tmp = xstrdup(options); + option = strtok(tmp, ":,"); + + while (option) { + + enum { + MODE_ADD, MODE_REMOVE + } mode; + + switch (*option) { + + case '!': + + case '-': + mode = MODE_REMOVE; + ++option; + break; + + case '+': + mode = MODE_ADD; + ++option; + break; + + default: + mode = MODE_ADD; + break; + } + + struct ssl_option *opt = NULL; + for (struct ssl_option *opttmp = ssl_options; opttmp->name; ++opttmp) { + if (strcmp(opttmp->name, option) == 0) { + opt = opttmp; + break; + } + } + + long value = 0; + if (opt) + value = opt->value; + else if (strncmp(option, "0x", 2) == 0) { + /* Special case.. hex specification */ + value = strtol(option + 2, NULL, 16); + } else { + fatalf("Unknown SSL option '%s'", option); + value = 0; /* Keep GCC happy */ + } + + switch (mode) { + + case MODE_ADD: + op |= value; + break; + + case MODE_REMOVE: + op &= ~value; + break; + } + + option = strtok(NULL, ":,"); + } + + safe_free(tmp); + } + +#if SSL_OP_NO_SSLv2 + // compliance with RFC 6176: Prohibiting Secure Sockets Layer (SSL) Version 2.0 + op = op | SSL_OP_NO_SSLv2; +#endif + return op; +} + +long +Security::ParseFlags(const SBuf &flags) +{ + if (flags.isEmpty()) + return 0; + + static struct { + SBuf label; + long mask; + } flagTokens[] = { + { SBuf("NO_DEFAULT_CA"), SSL_FLAG_NO_DEFAULT_CA }, + { SBuf("DELAYED_AUTH"), SSL_FLAG_DELAYED_AUTH }, + { SBuf("DONT_VERIFY_PEER"), SSL_FLAG_DONT_VERIFY_PEER }, + { SBuf("DONT_VERIFY_DOMAIN"), SSL_FLAG_DONT_VERIFY_DOMAIN }, + { SBuf("NO_SESSION_REUSE"), SSL_FLAG_NO_SESSION_REUSE }, +#if X509_V_FLAG_CRL_CHECK + { SBuf("VERIFY_CRL"), SSL_FLAG_VERIFY_CRL }, + { SBuf("VERIFY_CRL_ALL"), SSL_FLAG_VERIFY_CRL_ALL }, +#endif + { SBuf(), 0 } + }; + + ::Parser::Tokenizer tok(flags); + static const CharacterSet delims("Flag-delimiter", ":,"); + + long fl = 0; + do { + long found = 0; + for (size_t i = 0; flagTokens[i].mask; ++i) { + if (tok.skip(flagTokens[i].label) == 0) { + found = flagTokens[i].mask; + break; + } + } + if (!found) + fatalf("Unknown SSL flag '" SQUIDSBUFPH "'", SQUIDSBUFPRINT(tok.remaining())); + fl |= found; + } while (tok.skipOne(delims)); + + return fl; +} + void parse_securePeerOptions(Security::PeerOptions *opt) { diff --cc src/security/PeerOptions.h index 15510c9088,7defc9a862..c05d02c4b9 --- a/src/security/PeerOptions.h +++ b/src/security/PeerOptions.h @@@ -29,9 -28,9 +29,12 @@@ public /// reset the configuration details to default void clear() {*this = PeerOptions();} - /// generate a security context from these configured options - Security::ContextPointer createContext(bool setOptions); + /// generate a security client-context from these configured options + Security::ContextPointer createClientContext(bool setOptions); + ++ /// sync the context options with tls-min-version=N configuration ++ void updateTlsVersionLimits(); + SBuf certFile; ///< path of file containing PEM format X509 certificate SBuf privateKeyFile; ///< path of file containing private key in PEM format SBuf sslOptions; ///< library-specific options string @@@ -40,14 -39,17 +43,18 @@@ SBuf crlFile; ///< path of file containing Certificate Revoke List SBuf sslCipher; - SBuf sslFlags; + SBuf sslFlags; ///< flags defining what TLS operations Squid performs SBuf sslDomain; + SBuf tlsMinVersion; ///< version label for minimum TLS version to permit + long parsedOptions; ///< parsed value of sslOptions + long parsedFlags; ///< parsed value of sslFlags + private: int sslVersion; + public: /// whether transport encryption (TLS/SSL) is to be used on connections to the peer bool encryptTransport; }; diff --cc src/ssl/support.cc index 300dc8b14c,e2ea36d74c..a7aaaa9479 --- a/src/ssl/support.cc +++ b/src/ssl/support.cc @@@ -542,8 -867,12 +592,12 @@@ static boo configureSslContext(SSL_CTX *sslContext, AnyP::PortCfg &port) { int ssl_error; - SSL_CTX_set_options(sslContext, port.sslOptions); + SSL_CTX_set_options(sslContext, port.secure.parsedOptions); + #if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) + SSL_CTX_set_info_callback(sslContext, ssl_info_cb); + #endif + if (port.sslContextSessionId) SSL_CTX_set_session_id_context(sslContext, (const unsigned char *)port.sslContextSessionId, strlen(port.sslContextSessionId)); @@@ -570,10 -899,20 +624,20 @@@ debugs(83, 9, "Setting RSA key generation callback."); SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb); + if (port.eecdhCurve) { + debugs(83, 9, "Setting Ephemeral ECDH curve to " << port.eecdhCurve << "."); + + if (!configureSslEECDH(sslContext, port.eecdhCurve)) { + ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Unable to configure Ephemeral ECDH: " << ERR_error_string(ssl_error, NULL)); + return false; + } + } + debugs(83, 9, "Setting CA certificate locations."); - const char *cafile = port.cafile ? port.cafile : port.clientca; - if ((cafile || port.capath) && !SSL_CTX_load_verify_locations(sslContext, cafile, port.capath)) { + const char *cafile = port.secure.caFile.isEmpty() ? port.clientca : port.secure.caFile.c_str(); + if ((cafile || !port.secure.caDir.isEmpty()) && !SSL_CTX_load_verify_locations(sslContext, cafile, port.secure.caDir.c_str())) { ssl_error = ERR_get_error(); debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL)); } @@@ -586,9 -925,15 +650,15 @@@ if (port.clientCA.get()) { ERR_clear_error(); - SSL_CTX_set_client_CA_list(sslContext, port.clientCA.get()); + if (STACK_OF(X509_NAME) *clientca = SSL_dup_CA_list(port.clientCA.get())) { + SSL_CTX_set_client_CA_list(sslContext, clientca); + } else { + ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to dupe the client CA list: " << ERR_error_string(ssl_error, NULL)); + return false; + } - if (port.sslContextFlags & SSL_FLAG_DELAYED_AUTH) { + if (port.secure.parsedFlags & SSL_FLAG_DELAYED_AUTH) { debugs(83, 9, "Not requesting client certificates until acl processing requires one"); SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); } else { @@@ -632,26 -977,37 +702,25 @@@ SSL_CTX * sslCreateServerContext(AnyP::PortCfg &port) { - int ssl_error; - const char *keyfile, *certfile; - certfile = port.cert; - keyfile = port.key; - ssl_initialize(); - - if (!keyfile) - keyfile = certfile; - - if (!certfile) - certfile = keyfile; - SSL_CTX *sslContext = SSL_CTX_new(port.contextMethod); - int ssl_error; if (sslContext == NULL) { -- ssl_error = ERR_get_error(); ++ int ssl_error = ERR_get_error(); debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate SSL context: " << ERR_error_string(ssl_error, NULL)); return NULL; } if (!SSL_CTX_use_certificate(sslContext, port.signingCert.get())) { -- ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL)); ++ int ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << port.secure.certFile << "': " << ERR_error_string(ssl_error, NULL)); SSL_CTX_free(sslContext); return NULL; } if (!SSL_CTX_use_PrivateKey(sslContext, port.signPkey.get())) { -- ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL)); ++ int ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << port.secure.privateKeyFile << "': " << ERR_error_string(ssl_error, NULL)); SSL_CTX_free(sslContext); return NULL; } @@@ -716,141 -1072,48 +785,45 @@@ int Ssl::OpenSSLtoSquidSSLVersion(int s return 1; } - #if OPENSSL_VERSION_NUMBER < 0x00909000L - SSL_METHOD * - #else - const SSL_METHOD * - #endif - Ssl::method(int version) + #if defined(TLSEXT_TYPE_next_proto_neg) + //Dummy next_proto_neg callback + static int + ssl_next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) { - switch (version) { - - case 2: - debugs(83, DBG_IMPORTANT, "SSLv2 is not available in this Proxy."); - return NULL; - break; - - case 3: - debugs(83, 5, "Using SSLv3."); - return SSLv3_client_method(); - break; - - case 4: - debugs(83, 5, "Using TLSv1."); - return TLSv1_client_method(); - break; - - case 5: - #if OPENSSL_VERSION_NUMBER >= 0x10001000L // NP: not sure exactly which sub-version yet. - debugs(83, 5, "Using TLSv1.1."); - return TLSv1_1_client_method(); - #else - debugs(83, DBG_IMPORTANT, "TLSv1.1 is not available in this Proxy."); - return NULL; - #endif - break; - - case 6: - #if OPENSSL_VERSION_NUMBER >= 0x10001000L // NP: not sure exactly which sub-version yet. - debugs(83, 5, "Using TLSv1.2"); - return TLSv1_2_client_method(); - #else - debugs(83, DBG_IMPORTANT, "TLSv1.2 is not available in this Proxy."); - return NULL; - #endif - break; - - case 1: - - default: - debugs(83, 5, "Using SSLv2/SSLv3."); - return SSLv23_client_method(); - break; - } - - //Not reached - return NULL; + static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'}; + (void)SSL_select_next_proto(out, outlen, in, inlen, supported_protos, sizeof(supported_protos)); + return SSL_TLSEXT_ERR_OK; } - - const SSL_METHOD * - Ssl::serverMethod(int version) - { - switch (version) { - - case 2: - debugs(83, DBG_IMPORTANT, "SSLv2 is not available in this Proxy."); - return NULL; - break; - - case 3: - debugs(83, 5, "Using SSLv3."); - return SSLv3_server_method(); - break; - - case 4: - debugs(83, 5, "Using TLSv1."); - return TLSv1_server_method(); - break; - - case 5: - #if OPENSSL_VERSION_NUMBER >= 0x10001000L // NP: not sure exactly which sub-version yet. - debugs(83, 5, "Using TLSv1.1."); - return TLSv1_1_server_method(); - #else - debugs(83, DBG_IMPORTANT, "TLSv1.1 is not available in this Proxy."); - return NULL; - #endif - break; - - case 6: - #if OPENSSL_VERSION_NUMBER >= 0x10001000L // NP: not sure exactly which sub-version yet. - debugs(83, 5, "Using TLSv1.2"); - return TLSv1_2_server_method(); - #else - debugs(83, DBG_IMPORTANT, "TLSv1.2 is not available in this Proxy."); - return NULL; #endif - break; - - case 1: - - default: - debugs(83, 5, "Using SSLv2/SSLv3."); - return SSLv23_server_method(); - break; - } - - //Not reached - return NULL; - } SSL_CTX * - sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, long options, long fl, const char *CAfile, const char *CApath, const char *CRLfile) -sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile) ++sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, long options, long fl, const char *CAfile, const char *CApath, const char *CRLfile) { -- int ssl_error; - Ssl::ContextMethod method; - SSL_CTX * sslContext; - long fl = Ssl::parse_flags(flags); -- ssl_initialize(); - if (!(method = Ssl::method(version))) - return NULL; - - sslContext = SSL_CTX_new(method); + #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) + SSL_CTX *sslContext = SSL_CTX_new(TLS_client_method()); + #else + SSL_CTX *sslContext = SSL_CTX_new(SSLv23_client_method()); + #endif if (sslContext == NULL) { -- ssl_error = ERR_get_error(); ++ int ssl_error = ERR_get_error(); fatalf("Failed to allocate SSL context: %s\n", ERR_error_string(ssl_error, NULL)); } - SSL_CTX_set_options(sslContext, Ssl::parse_options(options)); + SSL_CTX_set_options(sslContext, options); + #if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) + SSL_CTX_set_info_callback(sslContext, ssl_info_cb); + #endif + if (*cipher) { debugs(83, 5, "Using chiper suite " << cipher << "."); if (!SSL_CTX_set_cipher_list(sslContext, cipher)) { -- ssl_error = ERR_get_error(); ++ int ssl_error = ERR_get_error(); fatalf("Failed to set SSL cipher suite '%s': %s\n", cipher, ERR_error_string(ssl_error, NULL)); } @@@ -860,7 -1123,7 +833,7 @@@ debugs(83, DBG_IMPORTANT, "Using certificate in " << certfile); if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) { -- ssl_error = ERR_get_error(); ++ int ssl_error = ERR_get_error(); fatalf("Failed to acquire SSL certificate '%s': %s\n", certfile, ERR_error_string(ssl_error, NULL)); } @@@ -869,7 -1132,7 +842,7 @@@ ssl_ask_password(sslContext, keyfile); if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) { -- ssl_error = ERR_get_error(); ++ int ssl_error = ERR_get_error(); fatalf("Failed to acquire SSL private key '%s': %s\n", keyfile, ERR_error_string(ssl_error, NULL)); } @@@ -877,7 -1140,7 +850,7 @@@ debugs(83, 5, "Comparing private and public SSL keys."); if (!SSL_CTX_check_private_key(sslContext)) { -- ssl_error = ERR_get_error(); ++ int ssl_error = ERR_get_error(); fatalf("SSL private key '%s' does not match public key '%s': %s\n", certfile, keyfile, ERR_error_string(ssl_error, NULL)); } @@@ -897,7 -1160,7 +870,7 @@@ debugs(83, 9, "Setting CA certificate locations."); if ((*CAfile || *CApath) && !SSL_CTX_load_verify_locations(sslContext, CAfile, CApath)) { -- ssl_error = ERR_get_error(); ++ int ssl_error = ERR_get_error(); debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL)); } @@@ -916,7 -1179,7 +889,7 @@@ if (!(fl & SSL_FLAG_NO_DEFAULT_CA) && !SSL_CTX_set_default_verify_paths(sslContext)) { -- ssl_error = ERR_get_error(); ++ int ssl_error = ERR_get_error(); debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL)); } diff --cc src/ssl/support.h index 64a9d76a1b,6e9e3237be..681e0da4dc --- a/src/ssl/support.h +++ b/src/ssl/support.h @@@ -92,7 -92,7 +92,7 @@@ typedef CbDataList Cert SSL_CTX *sslCreateServerContext(AnyP::PortCfg &port); /// \ingroup ServerProtocolSSLAPI - SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, long options, long flags, const char *CAfile, const char *CApath, const char *CRLfile); -SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile); ++SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, long options, long flags, const char *CAfile, const char *CApath, const char *CRLfile); /// \ingroup ServerProtocolSSLAPI int ssl_read_method(int, char *, int); diff --cc src/tests/stub_libsecurity.cc index b274c3b4b3,ec7903251e..32cce654b4 --- a/src/tests/stub_libsecurity.cc +++ b/src/tests/stub_libsecurity.cc @@@ -19,8 -19,6 +19,9 @@@ std::ostream &Security::operator <<(std #include "security/PeerOptions.h" Security::PeerOptions Security::ProxyOutgoingConfig; void Security::PeerOptions::parse(char const*) STUB -Security::ContextPointer Security::PeerOptions::createContext(bool) STUB_RETVAL(NULL) +Security::ContextPointer Security::PeerOptions::createClientContext(bool) STUB_RETVAL(NULL) ++void Security::PeerOptions::updateTlsVersionLimits() STUB void parse_securePeerOptions(Security::PeerOptions *) STUB +long Security::ParseOptions(const char *) STUB_RETVAL(0) +long Security::ParseFlags(const SBuf &) STUB_RETVAL(0) diff --cc src/tests/stub_libsslsquid.cc index 2d131b772b,fe52495154..82c55ed490 --- a/src/tests/stub_libsslsquid.cc +++ b/src/tests/stub_libsslsquid.cc @@@ -57,7 -57,7 +57,7 @@@ bool CertError::operator == (const Cert bool CertError::operator != (const CertError &ce) const STUB_RETVAL(false) } // namespace Ssl SSL_CTX *sslCreateServerContext(AnyP::PortCfg &port) STUB_RETVAL(NULL) - SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, long options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile) STUB_RETVAL(NULL) -SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile) STUB_RETVAL(NULL) ++SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, long options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile) STUB_RETVAL(NULL) int ssl_read_method(int, char *, int) STUB_RETVAL(0) int ssl_write_method(int, const char *, int) STUB_RETVAL(0) void ssl_shutdown_method(SSL *ssl) STUB @@@ -73,9 -73,9 +73,8 @@@ namespace Ss //GETX509ATTRIBUTE GetX509Fingerprint; const char *BumpModeStr[] = {""}; long parse_flags(const char *flags) STUB_RETVAL(0) -long parse_options(const char *options) STUB_RETVAL(0) STACK_OF(X509_CRL) *loadCrl(const char *CRLFile, long &flags) STUB_RETVAL(NULL) DH *readDHParams(const char *dhfile) STUB_RETVAL(NULL) - ContextMethod contextMethod(int version) STUB_RETVAL(ContextMethod()) bool generateUntrustedCert(X509_Pointer & untrustedCert, EVP_PKEY_Pointer & untrustedPkey, X509_Pointer const & cert, EVP_PKEY_Pointer const & pkey) STUB_RETVAL(false) SSL_CTX * generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port) STUB_RETVAL(NULL) bool verifySslCertificate(SSL_CTX * sslContext, CertificateProperties const &properties) STUB_RETVAL(false)