http/libsquid-http.la \
parser/libsquid-parser.la \
dns/libdns.la \
-- security/libsecurity.la \
base/libbase.la \
libsquid.la \
ip/libip.la \
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 \
SquidList.h \
SquidList.cc \
mem_node.cc \
- Packer.cc \
Parsing.cc \
+ tests/stub_libsecurity.cc \
SquidMath.cc \
StatCounters.cc \
StatCounters.h \
#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
}
}
- sslContext = writeableCfg().secure.createContext(true);
+ 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.createClientContext(true);
+ }
+
theSessionFailures.configure(TheConfig.oldest_service_failure > 0 ?
TheConfig.oldest_service_failure : -1);
}
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),
- sslflags(NULL),
+ tls_dh(NULL),
sslContextSessionId(NULL),
generateHostCertificates(false),
dynamicCertMemCacheSize(std::numeric_limits<size_t>::max()),
clientVerifyCrls(),
clientCA(),
dhParams(),
- contextMethod(),
- sslContextFlags(0),
- sslOptions(0)
+ eecdhCurve(NULL),
+ contextMethod()
#endif
{
memset(&tcp_keepalive, 0, sizeof(tcp_keepalive));
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(sslflags);
+ safe_free(tls_dh);
safe_free(sslContextSessionId);
+ safe_free(eecdhCurve);
#endif
}
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 (sslflags)
- b->sslflags = xstrdup(sslflags);
+ if (tls_dh)
+ b->tls_dh = xstrdup(tls_dh);
if (sslContextSessionId)
b->sslContextSessionId = xstrdup(sslContextSessionId);
}
}
- 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) {
*/
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 *sslflags;
+ char *tls_dh;
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
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
};
} 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) {
- s->version = xatoi(token + 8);
- if (s->version < 1 || s->version > 6)
- self_destruct();
+ debugs(3, DBG_PARSE_NOTE(1), "UPGRADE WARNING: '" << token << "' is deprecated " <<
+ "in " << cfg_directive << ". Use 'options=' instead.");
- if (s->secure.sslVersion < 1 || s->secure.sslVersion > 4)
- self_destruct();
+ s->secure.parse(token);
} 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);
#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->sslflags)
- storeAppendPrintf(e, " sslflags=%s", s->sslflags);
-
+ if (s->tls_dh)
+ storeAppendPrintf(e, " tls-dh=%s", s->tls_dh);
+
if (s->sslContextSessionId)
storeAppendPrintf(e, " sslcontext=%s", s->sslContextSessionId);
#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
}
}
-// 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)
{
/// 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
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;
};
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));
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));
}
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 {
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;
}
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));
}
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));
}
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));
}
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));
}
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));
}
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));
}
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);
#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)
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
//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)