[squid-dev] [PATCH] crypto-ng: CA support for GnuTLS
Amos Jeffries
squid3 at treenet.co.nz
Sat Oct 3 08:44:07 UTC 2015
Shuffle the cafile= context logics to libsecurity class PeerOptions.
* Rename the parameter tls-cafile= and allow multiple cafile= entries to
be used in squid.conf.
* Document the capath= option as only supported by OpenSSL and LibreSSL.
* Add GnuTLS support for CA loading.
Although at this point GnuTLS contexts are not yet created.
Amos
-------------- next part --------------
=== modified file 'doc/release-notes/release-4.sgml'
--- doc/release-notes/release-4.sgml 2015-08-26 13:53:33 +0000
+++ doc/release-notes/release-4.sgml 2015-10-03 05:29:50 +0000
@@ -157,70 +157,73 @@
<tag>url_rewrite_timeout</tag>
<p>Squid times active requests to redirector. This option sets
the timeout value and the Squid reaction to a timed out
request.
</descrip>
<sect1>Changes to existing tags<label id="modifiedtags">
<p>
<descrip>
<tag>auth_param</tag>
<p>New parameter <em>queue-size=</em> to set the maximum number
of queued requests.
<tag>cache_peer</tag>
<p>New option <em>tls-min-version=1.N</em> to set minimum TLS version allowed.
<p>All <em>ssloptions=</em> values for SSLv2 configuration or disabling
have been removed.
<p>Removed <em>sslversion=</em> option. Use <em>tls-options=</em> instead.
<p>Manual squid.conf update may be required on upgrade.
+ <p>Replaced <em>sslcafile=</em> with <em>tls-cafile=</em> which takes multiple entries.
<tag>external_acl_type</tag>
<p>New parameter <em>queue-size=</em> to set the maximum number
of queued requests.
<tag>http_port</tag>
<p>New option <em>tls-min-version=1.N</em> to set minimum TLS version allowed.
<p>All <em>option=</em> values for SSLv2 configuration or disabling
have been removed.
<p>Removed <em>version=</em> option. Use <em>tls-options=</em> instead.
<p>New <em>options=SINGLE_ECDH_USE</em> parameter to enable ephemeral
ECDH key exchange.
<p>Deprecated <em>dhparams=</em> option. Use <em>tls-dh=</em> instead.
The new option allows to optionally specify an elliptic curve for
ephemeral ECDH by adding <em>curve-name:</em> in front of the
parameter file name.
<p>Manual squid.conf update may be required on upgrade.
+ <p>Replaced <em>cafile=</em> with <em>tls-cafile=</em> which takes multiple entries.
<tag>https_port</tag>
<p>New option <em>tls-min-version=1.N</em> to set minimum TLS version allowed.
<p>All <em>options=</em> values for SSLv2
configuration or disabling have been removed.
<p>Removed <em>version=</em> option. Use <em>tls-options=</em> instead.
<p>New <em>options=SINGLE_ECDH_USE</em> parameter to enable ephemeral
ECDH key exchange.
<p>Deprecated <em>dhparams=</em> option. Use <em>tls-dh=</em> instead.
The new option allows to optionally specify an elliptic curve for
ephemeral ECDH by adding <em>curve-name:</em> in front of the
parameter file name.
<p>Manual squid.conf update may be required on upgrade.
+ <p>Replaced <em>cafile=</em> with <em>tls-cafile=</em> which takes multiple entries.
<tag>icap_service</tag>
<p>New scheme <em>icaps://</em> to enable TLS/SSL connections to Secure ICAP
servers on port 11344.
<p>New <em>tls-cert=</em> option to set TLS client certificate to use.
<p>New <em>tls-key=</em> option to set TLS private key matching the client
certificate used.
<p>New <em>tls-min-version=1.N</em> option to set minimum TLS version allowed
on server connections.
<p>New <em>tls-options=</em> option to set OpenSSL library parameters.
<p>New <em>tls-flags=</em> option to set flags modifying Squid TLS operations.
<p>New <em>tls-cipher=</em> option to set a list of ciphers permitted.
<p>New <em>tls-cafile=</em> option to set a file with additional CA
certificate(s) to verify the server certificate.
<p>New <em>tls-crlfile=</em> option to set a file with a CRL to verify the
server certificate.
<p>New <em>tls-domain=</em> option to verify the server certificate domain.
<tag>refresh_pattern</tag>
<p>Removed <em>ignore-auth</em>. Its commonly desired behaviour is
@@ -239,40 +242,41 @@
<tag>url_rewrite_children</tag>
<p>New parameter <em>queue-size=</em> to set the maximum number
of queued requests.
</descrip>
<sect1>Removed tags<label id="removedtags">
<p>
<descrip>
<tag>cache_peer_domain</tag>
<p>Superceded by <em>cache_peer_access</em>. Use dstdomain ACL
in the access control list to restrict domains requested.
<tag>refresh_pattern</tag>
<p>Option <em>ignore-auth</em> removed. Its original intent was
to improve caching. HTTP/1.1 permits caching of authenticated
messages under conditions which Squid does check for and obey.
<tag>sslproxy_cafile</tag>
<p>Replaced by <em>tls_outgoing_options cafile=</em>.
+ Which now takes multiple entries.
<tag>sslproxy_capath</tag>
<p>Replaced by <em>tls_outgoing_options capath=</em>.
<tag>sslproxy_cipher</tag>
<p>Replaced by <em>tls_outgoing_options cipher=</em>.
<tag>sslproxy_client_certificate</tag>
<p>Replaced by <em>tls_outgoing_options cert=</em>.
<tag>sslproxy_client_key</tag>
<p>Replaced by <em>tls_outgoing_options key=</em>.
<tag>sslproxy_flags</tag>
<p>Replaced by <em>tls_outgoing_options flags=</em>.
<tag>sslproxy_options</tag>
<p>Replaced by <em>tls_outgoing_options options=</em>.
<p>All values for SSLv2 configuration or disabling have been removed.
<p>Manual squid.conf update may be required on upgrade.
=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc 2015-09-05 18:52:17 +0000
+++ src/cache_cf.cc 2015-09-30 13:01:19 +0000
@@ -3561,40 +3561,42 @@
"in " << cfg_directive << ". Use 'ssl-bump' instead.");
s->flags.tunnelSslBumping = true;
} else if (strcmp(token, "ssl-bump") == 0) {
s->flags.tunnelSslBumping = true;
} else if (strncmp(token, "cert=", 5) == 0) {
s->secure.parse(token);
} else if (strncmp(token, "key=", 4) == 0) {
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->secure.parse(token);
} else if (strncmp(token, "options=", 8) == 0) {
s->secure.parse(token);
} else if (strncmp(token, "cipher=", 7) == 0) {
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) {
+ debugs(3, DBG_PARSE_NOTE(1), "UPGRADE WARNING: '" << token << "' is deprecated " <<
+ "in " << cfg_directive << ". Use 'tls-cafile=' instead.");
s->secure.parse(token);
} else if (strncmp(token, "capath=", 7) == 0) {
s->secure.parse(token);
} else if (strncmp(token, "crlfile=", 8) == 0) {
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) {
s->secure.parse(token+3);
} else if (strncmp(token, "sslcontext=", 11) == 0) {
safe_free(s->sslContextSessionId);
s->sslContextSessionId = xstrdup(token + 11);
} else if (strcmp(token, "generate-host-certificates") == 0) {
s->generateHostCertificates = true;
@@ -3642,40 +3644,47 @@
self_destruct();
return;
}
char *token = ConfigParser::NextToken();
if (!token) {
self_destruct();
return;
}
AnyP::PortCfgPointer s = new AnyP::PortCfg();
s->transport = parsePortProtocol(protoName); // default; protocol=... overwrites
parsePortSpecification(s, token);
/* parse options ... */
while ((token = ConfigParser::NextToken())) {
parse_port_option(s, token);
}
+#if USE_OPENSSL
+ // if clientca has been defined but not cafile, then use it to verify
+ // but if cafile has been defined, only use that to verify
+ if (s->clientca && !s->secure.caFiles.size())
+ s->secure.caFiles.emplace_back(SBuf(s->clientca));
+#endif
+
if (s->transport.protocol == AnyP::PROTO_HTTPS) {
s->secure.encryptTransport = true;
#if USE_OPENSSL
/* ssl-bump on https_port configuration requires either tproxy or intercept, and vice versa */
const bool hijacked = s->flags.isIntercepted();
if (s->flags.tunnelSslBumping && !hijacked) {
debugs(3, DBG_CRITICAL, "FATAL: ssl-bump on https_port requires tproxy/intercept which is missing.");
self_destruct();
}
if (hijacked && !s->flags.tunnelSslBumping) {
debugs(3, DBG_CRITICAL, "FATAL: tproxy/intercept on https_port requires ssl-bump which is missing.");
self_destruct();
}
#endif
if (s->flags.proxySurrogate) {
debugs(3,DBG_CRITICAL, "FATAL: https_port: require-proxy-header option is not supported on HTTPS ports.");
self_destruct();
}
} else if (protoName.cmp("FTP") == 0) {
/* ftp_port does not support ssl-bump */
=== modified file 'src/cf.data.pre'
--- src/cf.data.pre 2015-08-30 01:07:47 +0000
+++ src/cf.data.pre 2015-09-30 13:39:34 +0000
@@ -1948,46 +1948,47 @@
The adopted curve should be specified
using the tls-dh option.
NO_TICKET
Disable use of RFC5077 session tickets.
Some servers may have problems
understanding the TLS extension due
to ambiguous specification in RFC4507.
ALL Enable various bug workarounds
suggested as "harmless" by OpenSSL
Be warned that this reduces SSL/TLS
strength to some attacks.
See the OpenSSL SSL_CTX_set_options documentation for a
more complete list.
clientca= File containing the list of CAs to use when
requesting a client certificate.
- cafile= File containing additional CA certificates to
- use when verifying client certificates. If unset
- clientca will be used.
+ tls-cafile= PEM file containing CA certificates to use when verifying
+ client certificates. If not configured clientca will be
+ used. May be repeated to load multiple files.
capath= Directory containing additional CA certificates
and CRL lists to use when verifying client certificates.
+ Requires OpenSSL or LibreSSL.
crlfile= File of additional CRL lists to use when verifying
the client certificate, in addition to CRLs stored in
the capath. Implies VERIFY_CRL flag below.
tls-dh=[curve:]file
File containing DH parameters for temporary/ephemeral DH key
exchanges, optionally prefixed by a curve for ephemeral ECDH
key exchanges.
See OpenSSL documentation for details on how to create the
DH parameter file. Supported curves for ECDH can be listed
using the "openssl ecparam -list_curves" command.
WARNING: EDH and EECDH ciphers will be silently disabled if
this option is not set.
sslflags= Various flags modifying the use of SSL:
DELAYED_AUTH
Don't request client certificates
immediately, but wait until acl processing
requires a certificate (not yet implemented).
@@ -2132,46 +2133,47 @@
The adopted curve should be specified
using the tls-dh option.
SSL_OP_NO_TICKET
Disable use of RFC5077 session tickets.
Some servers may have problems
understanding the TLS extension due
to ambiguous specification in RFC4507.
ALL Enable various bug workarounds
suggested as "harmless" by OpenSSL
Be warned that this reduces SSL/TLS
strength to some attacks.
See the OpenSSL SSL_CTX_set_options documentation for a
more complete list.
clientca= File containing the list of CAs to use when
requesting a client certificate.
- cafile= File containing additional CA certificates to
- use when verifying client certificates. If unset
- clientca will be used.
+ tls-cafile= PEM file containing CA certificates to use when verifying
+ client certificates. If not configured clientca will be
+ used. May be repeated to load multiple files.
capath= Directory containing additional CA certificates
and CRL lists to use when verifying client certificates.
+ Requires OpenSSL or LibreSSL.
crlfile= File of additional CRL lists to use when verifying
the client certificate, in addition to CRLs stored in
the capath. Implies VERIFY_CRL flag below.
tls-dh=[curve:]file
File containing DH parameters for temporary/ephemeral DH key
exchanges, optionally prefixed by a curve for ephemeral ECDH
key exchanges.
sslflags= Various flags modifying the use of SSL:
DELAYED_AUTH
Don't request client certificates
immediately, but wait until acl processing
requires a certificate (not yet implemented).
NO_DEFAULT_CA
Don't use the default CA lists built in
to OpenSSL.
NO_SESSION_REUSE
Don't allow for session reuse. Each connection
@@ -2630,45 +2632,46 @@
NO_TLSv1_2 Disallow the use of TLSv1.2
SINGLE_DH_USE
Always create a new key when using
temporary/ephemeral DH key exchanges
SSL_OP_NO_TICKET
Disable use of RFC5077 session tickets.
Some servers may have problems
understanding the TLS extension due
to ambiguous specification in RFC4507.
ALL Enable various bug workarounds
suggested as "harmless" by OpenSSL
Be warned that this reduces SSL/TLS
strength to some attacks.
See the OpenSSL SSL_CTX_set_options documentation for a
more complete list.
- cafile=... A file containing additional CA certificates to use
- when verifying the peer certificate.
-
- capath=... A directory containing additional CA certificates to
+ cafile= PEM file containing CA certificates to use when verifying
+ the peer certificate. May be repeated to load multiple files.
+
+ capath= A directory containing additional CA certificates to
use when verifying the peer certificate.
+ Requires OpenSSL or LibreSSL.
crlfile=... A certificate revocation list file to use when
verifying the peer certificate.
flags=... Specify various flags modifying the TLS implementation:
DONT_VERIFY_PEER
Accept certificates even if they fail to
verify.
NO_DEFAULT_CA
Don't use the default CA list built in
to OpenSSL.
DONT_VERIFY_DOMAIN
Don't verify the peer certificate
matches the server name
domain= The peer name as advertised in its certificate.
Used for verifying the correctness of the received peer
certificate. If not specified the peer hostname will be
used.
@@ -3367,45 +3370,46 @@
NO_TLSv1_2 Disallow the use of TLSv1.2
SINGLE_DH_USE
Always create a new key when using
temporary/ephemeral DH key exchanges
SSL_OP_NO_TICKET
Disable use of RFC5077 session tickets.
Some servers may have problems
understanding the TLS extension due
to ambiguous specification in RFC4507.
ALL Enable various bug workarounds
suggested as "harmless" by OpenSSL
Be warned that this reduces SSL/TLS
strength to some attacks.
See the OpenSSL SSL_CTX_set_options documentation for a
more complete list.
- sslcafile=... A file containing additional CA certificates to use
- when verifying the peer certificate.
+ tls-cafile= PEM file containing CA certificates to use when verifying
+ the peer certificate. May be repeated to load multiple files.
sslcapath=... A directory containing additional CA certificates to
use when verifying the peer certificate.
+ Requires OpenSSL or LibreSSL.
sslcrlfile=... A certificate revocation list file to use when
verifying the peer certificate.
sslflags=... Specify various flags modifying the SSL implementation:
DONT_VERIFY_PEER
Accept certificates even if they fail to
verify.
NO_DEFAULT_CA
Don't use the default CA list built in
to OpenSSL.
DONT_VERIFY_DOMAIN
Don't verify the peer certificate
matches the server name
ssldomain= The peer name as advertised in it's certificate.
Used for verifying the correctness of the received peer
@@ -8524,48 +8528,50 @@
NO_SSLv3 Disallow the use of SSLv3
NO_TLSv1 Disallow the use of TLSv1.0
NO_TLSv1_1 Disallow the use of TLSv1.1
NO_TLSv1_2 Disallow the use of TLSv1.2
SINGLE_DH_USE
Always create a new key when using
temporary/ephemeral DH key exchanges
ALL Enable various bug workarounds
suggested as "harmless" by OpenSSL
Be warned that this reduces SSL/TLS
strength to some attacks.
See the OpenSSL SSL_CTX_set_options documentation for a
more complete list. Options relevant only to SSLv2 are
not supported.
- tls-cafile=... A PEM file containing additional CA certificates to use
- when verifying the icap server certificate. Used
- to specify intermediate CA certificate(s) if not sent
- by the server. Or the full CA chain for the server
- when using the NO_DEFAULT_CA flag.
+ tls-cafile= PEM file containing CA certificates to use when verifying
+ the icap server certificate.
+ Use to specify intermediate CA certificate(s) if not sent
+ by the server. Or the full CA chain for the server when
+ using the NO_DEFAULT_CA flag.
+ May be repeated to load multiple files.
tls-capath=... A directory containing additional CA certificates to
use when verifying the icap server certificate.
+ Requires OpenSSL or LibreSSL.
tls-crlfile=... A certificate revocation list file to use when
verifying the icap server certificate.
tls-flags=... Specify various flags modifying the Squid TLS implementation:
DONT_VERIFY_PEER
Accept certificates even if they fail to
verify.
NO_DEFAULT_CA
Don't use the default CA list built into
OpenSSL.
DONT_VERIFY_DOMAIN
Don't verify the icap server certificate
matches the server name
tls-domain= The icap server name as advertised in it's certificate.
Used for verifying the correctness of the received icap
server certificate. If not specified the icap server
hostname extracted from ICAP URI will be used.
=== modified file 'src/security/Context.h'
--- src/security/Context.h 2015-03-21 11:58:32 +0000
+++ src/security/Context.h 2015-10-02 18:51:31 +0000
@@ -10,31 +10,31 @@
#define SQUID_SRC_SECURITY_CONTEXT_H
#if USE_OPENSSL
#if HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
#endif
#endif
#if USE_GNUTLS
#if HAVE_GNUTLS_GNUTLS_H
#include <gnutls/gnutls.h>
#endif
#endif
namespace Security {
#if USE_OPENSSL
typedef SSL_CTX* ContextPointer;
#elif USE_GNUTLS
-typedef gnutls_certificate_credentials_t* ContextPointer;
+typedef gnutls_certificate_credentials_t ContextPointer;
#else
// use void* so we can check against NULL
typedef void* ContextPointer;
#endif
} // namespace Security
#endif /* SQUID_SRC_SECURITY_CONTEXT_H */
=== modified file 'src/security/PeerOptions.cc'
--- src/security/PeerOptions.cc 2015-09-24 21:08:23 +0000
+++ src/security/PeerOptions.cc 2015-10-03 04:56:55 +0000
@@ -9,48 +9,48 @@
#include "squid.h"
#include "base/Packable.h"
#include "Debug.h"
#include "fatal.h"
#include "globals.h"
#include "parser/Tokenizer.h"
#include "parser/Tokenizer.h"
#include "Parsing.h"
#include "security/PeerOptions.h"
#if USE_OPENSSL
#include "ssl/support.h"
#endif
Security::PeerOptions Security::ProxyOutgoingConfig;
Security::PeerOptions::PeerOptions(const Security::PeerOptions &p) :
certFile(p.certFile),
privateKeyFile(p.privateKeyFile),
sslOptions(p.sslOptions),
- caFile(p.caFile),
caDir(p.caDir),
crlFile(p.crlFile),
sslCipher(p.sslCipher),
sslFlags(p.sslFlags),
sslDomain(p.sslDomain),
parsedOptions(p.parsedOptions),
parsedFlags(p.parsedFlags),
+ caFiles(p.caFiles),
parsedCrl(p.parsedCrl),
sslVersion(p.sslVersion),
encryptTransport(p.encryptTransport)
{
}
void
Security::PeerOptions::parse(const char *token)
{
if (!*token) {
// config says just "ssl" or "tls" (or "tls-")
encryptTransport = true;
return;
}
if (strncmp(token, "disable", 7) == 0) {
clear();
return;
}
@@ -58,84 +58,88 @@
certFile = SBuf(token + 5);
if (privateKeyFile.isEmpty())
privateKeyFile = certFile;
} else if (strncmp(token, "key=", 4) == 0) {
privateKeyFile = SBuf(token + 4);
if (certFile.isEmpty()) {
debugs(3, DBG_PARSE_NOTE(1), "WARNING: cert= option needs to be set before key= is used.");
certFile = privateKeyFile;
}
} else if (strncmp(token, "version=", 8) == 0) {
debugs(0, DBG_PARSE_NOTE(1), "UPGRADE WARNING: SSL version= is deprecated. Use options= to limit protocols instead.");
sslVersion = xatoi(token + 8);
} else if (strncmp(token, "min-version=", 12) == 0) {
tlsMinVersion = SBuf(token + 12);
} else if (strncmp(token, "options=", 8) == 0) {
sslOptions = SBuf(token + 8);
parsedOptions = parseOptions();
} else if (strncmp(token, "cipher=", 7) == 0) {
sslCipher = SBuf(token + 7);
} else if (strncmp(token, "cafile=", 7) == 0) {
- caFile = SBuf(token + 7);
+ caFiles.emplace_back(SBuf(token + 7));
} else if (strncmp(token, "capath=", 7) == 0) {
caDir = SBuf(token + 7);
+#if !USE_OPENSSL
+ debugs(3, DBG_PARSE_NOTE(1), "WARNING: capath= option requires --with-openssl.");
+#endif
} else if (strncmp(token, "crlfile=", 8) == 0) {
crlFile = SBuf(token + 8);
loadCrlFile();
} else if (strncmp(token, "flags=", 6) == 0) {
if (parsedFlags != 0) {
debugs(3, DBG_PARSE_NOTE(1), "WARNING: Overwriting flags=" << sslFlags << " with " << SBuf(token + 6));
}
sslFlags = SBuf(token + 6);
parsedFlags = parseFlags();
} else if (strncmp(token, "domain=", 7) == 0) {
sslDomain = SBuf(token + 7);
} else {
debugs(3, DBG_CRITICAL, "ERROR: Unknown TLS option '" << token << "'");
return;
}
encryptTransport = true;
}
void
Security::PeerOptions::dumpCfg(Packable *p, const char *pfx) const
{
if (!encryptTransport) {
p->appendf(" %sdisable", pfx);
return; // no other settings are relevant
}
if (!certFile.isEmpty())
p->appendf(" %scert=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(certFile));
if (!privateKeyFile.isEmpty() && privateKeyFile != certFile)
p->appendf(" %skey=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(privateKeyFile));
if (!sslOptions.isEmpty())
p->appendf(" %soptions=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslOptions));
if (!sslCipher.isEmpty())
p->appendf(" %scipher=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslCipher));
- if (!caFile.isEmpty())
- p->appendf(" %scafile=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(caFile));
+ for (auto i : caFiles) {
+ p->appendf(" %scafile=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(i));
+ }
if (!caDir.isEmpty())
p->appendf(" %scapath=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(caDir));
if (!crlFile.isEmpty())
p->appendf(" %scrlfile=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(crlFile));
if (!sslFlags.isEmpty())
p->appendf(" %sflags=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(sslFlags));
}
void
Security::PeerOptions::updateTlsVersionLimits()
{
if (!tlsMinVersion.isEmpty()) {
::Parser::Tokenizer tok(tlsMinVersion);
int64_t v = 0;
if (tok.skip('1') && tok.skip('.') && tok.int64(v, 10, false, 1) && v <= 3) {
// only account for TLS here - SSL versions are handled by options= parameter
// avoid affecting options= parameter in cachemgr config report
@@ -174,51 +178,54 @@
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;
+ Security::ContextPointer t = nullptr;
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(), sslCipher.c_str(),
- (setOptions ? parsedOptions : 0), parsedFlags,
- caFile.c_str(), caDir.c_str());
+ (setOptions ? parsedOptions : 0), parsedFlags);
#endif
- updateContextCrl(t);
+ if (t) {
+ updateContextCa(t);
+ updateContextCrl(t);
+ }
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
},
@@ -459,40 +466,74 @@
{
parsedCrl.clear();
if (crlFile.isEmpty())
return;
#if USE_OPENSSL
BIO *in = BIO_new_file(crlFile.c_str(), "r");
if (!in) {
debugs(83, 2, "WARNING: Failed to open CRL file " << crlFile);
return;
}
while (X509_CRL *crl = PEM_read_bio_X509_CRL(in,NULL,NULL,NULL)) {
parsedCrl.emplace_back(Security::CrlPointer(crl));
}
BIO_free(in);
#endif
}
void
+Security::PeerOptions::updateContextCa(Security::ContextPointer &ctx)
+{
+ debugs(83, 8, "Setting CA certificate locations.");
+
+ for (auto i : caFiles) {
+#if USE_OPENSSL
+ if (!SSL_CTX_load_verify_locations(ctx, i.c_str(), caDir.c_str())) {
+ const int ssl_error = ERR_get_error();
+ debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL));
+ }
+#elif USE_GNUTLS
+ if (gnutls_certificate_set_x509_trust_file(ctx, i.c_str(), GNUTLS_X509_FMT_PEM) < 0) {
+ debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location: " << i);
+ }
+#endif
+ }
+
+ if ((parsedFlags & SSL_FLAG_NO_DEFAULT_CA))
+ return;
+
+#if USE_OPENSSL
+ if (!SSL_CTX_set_default_verify_paths(ctx)) {
+ const int ssl_error = ERR_get_error();
+ debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default trusted CA : "
+ << ERR_error_string(ssl_error, NULL));
+ }
+#elif USE_GNUTLS
+ if (gnutls_certificate_set_x509_system_trust(ctx) != GNUTLS_E_SUCCESS) {
+ debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default trusted CA.");
+ }
+#endif
+}
+
+void
Security::PeerOptions::updateContextCrl(Security::ContextPointer &ctx)
{
#if USE_OPENSSL
bool verifyCrl = false;
X509_STORE *st = SSL_CTX_get_cert_store(ctx);
if (parsedCrl.size()) {
for (auto &i : parsedCrl) {
if (!X509_STORE_add_crl(st, i.get()))
debugs(83, 2, "WARNING: Failed to add CRL");
else
verifyCrl = true;
}
}
#if X509_V_FLAG_CRL_CHECK
if ((parsedFlags & SSL_FLAG_VERIFY_CRL_ALL))
X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
else if (verifyCrl || (parsedFlags & SSL_FLAG_VERIFY_CRL))
X509_STORE_set_flags(st, X509_V_FLAG_CRL_CHECK);
#endif
=== modified file 'src/security/PeerOptions.h'
--- src/security/PeerOptions.h 2015-09-24 21:08:23 +0000
+++ src/security/PeerOptions.h 2015-09-30 13:53:12 +0000
@@ -20,68 +20,71 @@
/// TLS squid.conf settings for a remote server peer
class PeerOptions
{
public:
PeerOptions() : parsedOptions(0), parsedFlags(0), sslVersion(0), encryptTransport(false) {}
PeerOptions(const PeerOptions &);
/// parse a TLS squid.conf option
void parse(const char *);
/// reset the configuration details to default
void clear() {*this = PeerOptions();}
/// 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();
+ /// setup the CA details for the given context
+ void updateContextCa(Security::ContextPointer &);
+
/// setup the CRL details for the given context
void updateContextCrl(Security::ContextPointer &);
/// output squid.conf syntax with 'pfx' prefix on parameters for the stored settings
void dumpCfg(Packable *, const char *pfx) const;
private:
long parseOptions();
long parseFlags();
void loadCrlFile();
public:
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 caFile; ///< path of file containing trusted Certificate Authority
SBuf caDir; ///< path of directory containing a set of trusted Certificate Authorities
SBuf crlFile; ///< path of file containing Certificate Revoke List
SBuf sslCipher;
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
+ std::list<SBuf> caFiles; ///< paths of files containing trusted Certificate Authority
Security::CertRevokeList parsedCrl; ///< CRL to use when verifying the remote end certificate
private:
int sslVersion;
public:
/// whether transport encryption (TLS/SSL) is to be used on connections to the peer
bool encryptTransport;
};
/// configuration options for DIRECT server access
extern PeerOptions ProxyOutgoingConfig;
} // namespace Security
// parse the tls_outgoing_options directive
void parse_securePeerOptions(Security::PeerOptions *);
#define free_securePeerOptions(x) Security::ProxyOutgoingConfig.clear()
#define dump_securePeerOptions(e,n,x) do { (e)->appendf(n); (x).dumpCfg((e),""); (e)->append("\n",1); } while(false)
=== modified file 'src/ssl/support.cc'
--- src/ssl/support.cc 2015-09-24 21:08:23 +0000
+++ src/ssl/support.cc 2015-09-30 12:26:01 +0000
@@ -559,53 +559,41 @@
if (!SSL_CTX_set_cipher_list(sslContext, port.secure.sslCipher.c_str())) {
ssl_error = ERR_get_error();
debugs(83, DBG_CRITICAL, "ERROR: Failed to set SSL cipher suite '" << port.secure.sslCipher << "': " << ERR_error_string(ssl_error, NULL));
return false;
}
}
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.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.secure.parsedFlags & SSL_FLAG_NO_DEFAULT_CA) &&
- !SSL_CTX_set_default_verify_paths(sslContext)) {
- ssl_error = ERR_get_error();
- debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL));
- }
+ port.secure.updateContextCa(sslContext);
if (port.clientCA.get()) {
ERR_clear_error();
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.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 {
debugs(83, 9, "Requiring client certificates.");
SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
}
port.secure.updateContextCrl(sslContext);
@@ -695,41 +683,41 @@
debugs(83, DBG_CRITICAL, "ERROR: Configuring static SSL context");
SSL_CTX_free(sslContext);
return NULL;
}
return sslContext;
}
#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)
{
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;
}
#endif
SSL_CTX *
-sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, long options, long fl, const char *CAfile, const char *CApath)
+sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, long options, long fl)
{
ssl_initialize();
#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) {
const 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, options);
#if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
SSL_CTX_set_info_callback(sslContext, ssl_info_cb);
#endif
@@ -765,53 +753,40 @@
debugs(83, 5, "Comparing private and public SSL keys.");
if (!SSL_CTX_check_private_key(sslContext)) {
const 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 RSA key generation callback.");
SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb);
if (fl & SSL_FLAG_DONT_VERIFY_PEER) {
debugs(83, 2, "NOTICE: Peer certificates are not verified for validity!");
SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
} else {
debugs(83, 9, "Setting certificate verification callback.");
SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
}
- debugs(83, 9, "Setting CA certificate locations.");
-
- if ((*CAfile || *CApath) && !SSL_CTX_load_verify_locations(sslContext, CAfile, CApath)) {
- const 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)) {
- const int ssl_error = ERR_get_error();
- debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL));
- }
-
#if defined(TLSEXT_TYPE_next_proto_neg)
SSL_CTX_set_next_proto_select_cb(sslContext, &ssl_next_proto_cb, NULL);
#endif
return sslContext;
}
/// \ingroup ServerProtocolSSLInternal
int
ssl_read_method(int fd, char *buf, int len)
{
SSL *ssl = fd_table[fd].ssl;
int i;
#if DONT_DO_THIS
if (!SSL_is_init_finished(ssl)) {
errno = ENOTCONN;
return -1;
}
=== modified file 'src/ssl/support.h'
--- src/ssl/support.h 2015-09-24 21:08:23 +0000
+++ src/ssl/support.h 2015-09-30 12:20:20 +0000
@@ -73,41 +73,41 @@
{
public:
ssl_error_t code; ///< certificate error code
Security::CertPointer cert; ///< certificate with the above error code
CertError(ssl_error_t anErr, X509 *aCert);
CertError(CertError const &err);
CertError & operator = (const CertError &old);
bool operator == (const CertError &ce) const;
bool operator != (const CertError &ce) const;
};
/// Holds a list of certificate SSL errors
typedef CbDataList<Ssl::CertError> CertErrors;
} //namespace Ssl
/// \ingroup ServerProtocolSSLAPI
SSL_CTX *sslCreateServerContext(AnyP::PortCfg &port);
/// \ingroup ServerProtocolSSLAPI
-SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, long options, long flags, const char *CAfile, const char *CApath);
+SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, long options, long flags);
/// \ingroup ServerProtocolSSLAPI
int ssl_read_method(int, char *, int);
/// \ingroup ServerProtocolSSLAPI
int ssl_write_method(int, const char *, int);
/// \ingroup ServerProtocolSSLAPI
void ssl_shutdown_method(SSL *ssl);
/// \ingroup ServerProtocolSSLAPI
const char *sslGetUserEmail(SSL *ssl);
/// \ingroup ServerProtocolSSLAPI
const char *sslGetUserAttribute(SSL *ssl, const char *attribute_name);
/// \ingroup ServerProtocolSSLAPI
const char *sslGetCAAttribute(SSL *ssl, const char *attribute_name);
/// \ingroup ServerProtocolSSLAPI
=== modified file 'src/tests/stub_libsecurity.cc'
--- src/tests/stub_libsecurity.cc 2015-09-24 21:08:23 +0000
+++ src/tests/stub_libsecurity.cc 2015-09-30 12:21:00 +0000
@@ -4,26 +4,27 @@
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
* Please see the COPYING and CONTRIBUTORS files for details.
*/
#include "squid.h"
#include "comm/Connection.h"
#define STUB_API "security/libsecurity.la"
#include "tests/STUB.h"
#include "security/EncryptorAnswer.h"
Security::EncryptorAnswer::~EncryptorAnswer() {}
std::ostream &Security::operator <<(std::ostream &os, const Security::EncryptorAnswer &) STUB_RETVAL(os)
#include "security/PeerOptions.h"
Security::PeerOptions Security::ProxyOutgoingConfig;
void Security::PeerOptions::parse(char const*) STUB
Security::ContextPointer Security::PeerOptions::createClientContext(bool) STUB_RETVAL(NULL)
void Security::PeerOptions::updateTlsVersionLimits() STUB
+void Security::PeerOptions::updateContextCa(Security::ContextPointer &) STUB
void Security::PeerOptions::updateContextCrl(Security::ContextPointer &) STUB
void Security::PeerOptions::dumpCfg(Packable*, char const*) const STUB
long Security::PeerOptions::parseOptions() STUB_RETVAL(0)
long Security::PeerOptions::parseFlags() STUB_RETVAL(0)
void parse_securePeerOptions(Security::PeerOptions *) STUB
=== modified file 'src/tests/stub_libsslsquid.cc'
--- src/tests/stub_libsslsquid.cc 2015-09-24 21:08:23 +0000
+++ src/tests/stub_libsslsquid.cc 2015-09-30 12:20:45 +0000
@@ -40,41 +40,41 @@
void Ssl::GlobalContextStorage::reconfigureStart() STUB
//Ssl::GlobalContextStorage Ssl::TheGlobalContextStorage;
#include "ssl/ErrorDetail.h"
Ssl::ssl_error_t parseErrorString(const char *name) STUB_RETVAL(0)
//const char *Ssl::getErrorName(ssl_error_t value) STUB_RETVAL(NULL)
Ssl::ErrorDetail::ErrorDetail(ssl_error_t err_no, X509 *, X509 *, const char *) STUB
Ssl::ErrorDetail::ErrorDetail(ErrorDetail const &) STUB
const String & Ssl::ErrorDetail::toString() const STUB_RETSTATREF(String)
#include "ssl/support.h"
namespace Ssl
{
//CertError::CertError(ssl_error_t anErr, X509 *aCert) STUB
//CertError::CertError(CertError const &err) STUB
CertError & CertError::operator = (const CertError &old) STUB_RETVAL(*this)
bool CertError::operator == (const CertError &ce) const STUB_RETVAL(false)
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, const char *cipher, long options, const char *flags, const char *CAfile, const char *CApath) STUB_RETVAL(NULL)
+SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, const char *cipher, long options, const char *flags) 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
const char *sslGetUserEmail(SSL *ssl) STUB_RETVAL(NULL)
const char *sslGetUserAttribute(SSL *ssl, const char *attribute_name) STUB_RETVAL(NULL)
const char *sslGetCAAttribute(SSL *ssl, const char *attribute_name) STUB_RETVAL(NULL)
const char *sslGetUserCertificatePEM(SSL *ssl) STUB_RETVAL(NULL)
const char *sslGetUserCertificateChainPEM(SSL *ssl) STUB_RETVAL(NULL)
namespace Ssl
{
//GETX509ATTRIBUTE GetX509UserAttribute;
//GETX509ATTRIBUTE GetX509CAAttribute;
//GETX509ATTRIBUTE GetX509Fingerprint;
const char *BumpModeStr[] = {""};
DH *readDHParams(const char *dhfile) STUB_RETVAL(NULL)
bool generateUntrustedCert(Security::CertPointer & untrustedCert, EVP_PKEY_Pointer & untrustedPkey, Security::CertPointer 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)
SSL_CTX * generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port) STUB_RETVAL(NULL)
void addChainToSslContext(SSL_CTX *sslContext, STACK_OF(X509) *certList) STUB
More information about the squid-dev
mailing list