Don't request client certificates
immediately, but wait until acl processing
requires a certificate (not yet implemented).
+ CONDITIONAL_AUTH
+ Request a client certificate during the TLS
+ handshake, but ignore certificate absence in
+ the TLS client Hello. If the client does
+ supply a certificate, it is validated.
NO_SESSION_REUSE
Don't allow for session reuse. Each connection
will result in a new SSL session.
#include "ssl/support.h"
#endif
+#include <bitset>
+
Security::PeerOptions Security::ProxyOutgoingConfig;
Security::PeerOptions::PeerOptions()
/**
* Parses the TLS flags squid.conf parameter
*/
-long
+Security::ParsedPortFlags
Security::PeerOptions::parseFlags()
{
if (sslFlags.isEmpty())
static struct {
SBuf label;
- long mask;
+ ParsedPortFlags 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("CONDITIONAL_AUTH"), SSL_FLAG_CONDITIONAL_AUTH },
{ SBuf("DONT_VERIFY_DOMAIN"), SSL_FLAG_DONT_VERIFY_DOMAIN },
{ SBuf("NO_SESSION_REUSE"), SSL_FLAG_NO_SESSION_REUSE },
#if X509_V_FLAG_CRL_CHECK
::Parser::Tokenizer tok(sslFlags);
static const CharacterSet delims("Flag-delimiter", ":,");
- long fl = 0;
+ ParsedPortFlags fl = 0;
do {
- long found = 0;
+ ParsedPortFlags found = 0;
for (size_t i = 0; flagTokens[i].mask; ++i) {
+ // XXX: skips FOO in FOOBAR, missing merged flags and trailing typos
if (tok.skip(flagTokens[i].label)) {
found = flagTokens[i].mask;
break;
fl |= found;
} while (tok.skipOne(delims));
+ const auto mutuallyExclusive =
+ SSL_FLAG_DONT_VERIFY_PEER|
+ SSL_FLAG_DELAYED_AUTH|
+ SSL_FLAG_CONDITIONAL_AUTH;
+ typedef std::bitset<sizeof(decltype(fl))> ParsedPortFlagBits;
+ if (ParsedPortFlagBits(fl & mutuallyExclusive).count() > 1) {
+ if (fl & SSL_FLAG_CONDITIONAL_AUTH)
+ throw TextException("CONDITIONAL_AUTH is not compatible with NO_DEFAULT_CA and DELAYED_AUTH flags", Here());
+ debugs(83, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: Mixtures of incompatible TLS flags" <<
+ " are deprecated and will become a fatal configuration error");
+ }
+
return fl;
}
#include "base/YesNoNone.h"
#include "ConfigParser.h"
+#include "security/forward.h"
#include "security/KeyData.h"
class Packable;
virtual void dumpCfg(Packable *, const char *pfx) const;
private:
- long parseFlags();
+ ParsedPortFlags parseFlags();
void loadCrlFile();
void loadKeysFile();
bool optsReparse = true;
public:
- long parsedFlags = 0; ///< parsed value of sslFlags
+ ParsedPortFlags parsedFlags = 0; ///< parsed value of sslFlags
std::list<Security::KeyData> certs; ///< details from the cert= and file= config parameters
std::list<SBuf> caFiles; ///< paths of files containing trusted Certificate Authority
return;
}
- if (parsedFlags & SSL_FLAG_DELAYED_AUTH) {
- debugs(83, 9, "Not requesting client certificates until acl processing requires one");
- SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_NONE, nullptr);
- } else {
- debugs(83, 9, "Requiring client certificates.");
- Ssl::SetupVerifyCallback(ctx);
- }
+ Ssl::ConfigurePeerVerification(ctx, parsedFlags);
updateContextCrl(ctx);
updateContextTrust(ctx);
} else {
- debugs(83, 9, "Not requiring any client certificates");
- SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_NONE, NULL);
+ Ssl::DisablePeerVerification(ctx);
}
#endif
}
#define SSL_FLAG_NO_SESSION_REUSE (1<<4)
#define SSL_FLAG_VERIFY_CRL (1<<5)
#define SSL_FLAG_VERIFY_CRL_ALL (1<<6)
+#define SSL_FLAG_CONDITIONAL_AUTH (1<<7)
/// Network/connection security abstraction layer
namespace Security
class ParsedOptions {}; // we never parse/use TLS options in this case
#endif
+/// bitmask representing configured http(s)_port `sslflags`
+/// as well tls_outgoing_options `flags`, cache_peer `sslflags`, and
+/// icap_service `tls-flags`
+typedef long ParsedPortFlags;
+
class PeerConnector;
class PeerOptions;
}
void
-Ssl::SetupVerifyCallback(Security::ContextPointer &ctx)
+Ssl::ConfigurePeerVerification(Security::ContextPointer &ctx, const Security::ParsedPortFlags flags)
{
- SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
+ int mode;
+
+ // assume each flag is exclusive; flags creator must check this assumption
+ if (flags & SSL_FLAG_DONT_VERIFY_PEER) {
+ debugs(83, DBG_IMPORTANT, "SECURITY WARNING: Peer certificates are not verified for validity!");
+ debugs(83, DBG_IMPORTANT, "UPGRADE NOTICE: The DONT_VERIFY_PEER flag is deprecated. Remove the clientca= option to disable client certificates.");
+ mode = SSL_VERIFY_NONE;
+ }
+ else if (flags & SSL_FLAG_DELAYED_AUTH) {
+ debugs(83, DBG_PARSE_NOTE(3), "not requesting client certificates until ACL processing requires one");
+ mode = SSL_VERIFY_NONE;
+ }
+ else if (flags & SSL_FLAG_CONDITIONAL_AUTH) {
+ debugs(83, DBG_PARSE_NOTE(3), "will request the client certificate but ignore its absense");
+ mode = SSL_VERIFY_PEER;
+ }
+ else {
+ debugs(83, DBG_PARSE_NOTE(3), "Requiring client certificates.");
+ mode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ }
+
+ SSL_CTX_set_verify(ctx.get(), mode, (mode != SSL_VERIFY_NONE) ? ssl_verify_cb : nullptr);
+}
+
+void
+Ssl::DisablePeerVerification(Security::ContextPointer &ctx)
+{
+ debugs(83, DBG_PARSE_NOTE(3), "Not requiring any client certificates");
+ SSL_CTX_set_verify(ctx.get(),SSL_VERIFY_NONE,nullptr);
}
// "dup" function for SSL_get_ex_new_index("cert_err_check")
}
bool
-Ssl::InitClientContext(Security::ContextPointer &ctx, Security::PeerOptions &peer, long fl)
+Ssl::InitClientContext(Security::ContextPointer &ctx, Security::PeerOptions &peer, Security::ParsedPortFlags fl)
{
if (!ctx)
return false;
MaybeSetupRsaCallback(ctx);
- if (fl & SSL_FLAG_DONT_VERIFY_PEER) {
- debugs(83, 2, "SECURITY WARNING: Peer certificates are not verified for validity!");
- SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_NONE, NULL);
- } else {
- debugs(83, 9, "Setting certificate verification callback.");
- Ssl::SetupVerifyCallback(ctx);
- }
+ Ssl::ConfigurePeerVerification(ctx, fl);
return true;
}
bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &);
/// initialize a TLS client context with OpenSSL specific settings
-bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, long flags);
+bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, Security::ParsedPortFlags);
/// set the certificate verify callback for a context
-void SetupVerifyCallback(Security::ContextPointer &);
+void ConfigurePeerVerification(Security::ContextPointer &, const Security::ParsedPortFlags);
+void DisablePeerVerification(Security::ContextPointer &);
/// if required, setup callback for generating ephemeral RSA keys
void MaybeSetupRsaCallback(Security::ContextPointer &);
{
int AskPasswordCb(char *, int, int, void *) STUB_RETVAL(0)
bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &) STUB_RETVAL(false)
-bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, const char *) STUB_RETVAL(false)
-void SetupVerifyCallback(Security::ContextPointer &) STUB
+bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, Security::ParsedPortFlags) STUB_RETVAL(false)
+void ConfigurePeerVerification(Security::ContextPointer &, const Security::ParsedPortFlags) STUB
+void DisablePeerVerification(Security::ContextPointer &) STUB
void MaybeSetupRsaCallback(Security::ContextPointer &) STUB
} // namespace Ssl
const char *sslGetUserEmail(SSL *ssl) STUB_RETVAL(NULL)