[squid-dev] [PATCH] cryptong: cleanup the context init sequence
Amos Jeffries
squid3 at treenet.co.nz
Wed May 25 11:03:46 UTC 2016
The libsecurity ServerOptions and PeerOptions class methods are now
supposed to be the API for creating SSL contexts for https_port,
cache_peer and outgoing connections.
Continue the API transition by making the callers of sslCreate*Context()
functions use the libsecurity API instead and repurpose the now obsolete
functions into the Ssl:: namespace to simply initialize the keying
material and other not yet converted state details of an existing context.
A side effect of this is that GnuTLS contexts are now actually created
and initialized as far as they can be.
SSL-Bump context initialization is not altered by this.
Amos
-------------- next part --------------
=== modified file 'src/anyp/PortCfg.cc'
--- src/anyp/PortCfg.cc 2016-01-01 00:12:18 +0000
+++ src/anyp/PortCfg.cc 2016-05-25 05:37:16 +0000
@@ -126,30 +126,28 @@
}
if (!signPkey)
debugs(3, DBG_IMPORTANT, "No SSL private key configured for " << AnyP::ProtocolType_str[transport.protocol] << "_port " << s);
Ssl::generateUntrustedCert(untrustedSigningCert, untrustedSignPkey,
signingCert, signPkey);
if (!untrustedSigningCert) {
char buf[128];
fatalf("Unable to generate signing SSL certificate for untrusted sites for %s_port %s", AnyP::ProtocolType_str[transport.protocol], s.toUrl(buf, sizeof(buf)));
}
if (clientca) {
clientCA.reset(SSL_load_client_CA_file(clientca));
if (clientCA.get() == NULL) {
fatalf("Unable to read client CAs! from %s", clientca);
}
}
- secure.updateTlsVersionLimits();
- secure.staticContext.reset(sslCreateServerContext(*this));
-
+ secure.staticContext.reset(secure.createStaticServerContext(*this));
if (!secure.staticContext) {
char buf[128];
fatalf("%s_port %s initialization error", AnyP::ProtocolType_str[transport.protocol], s.toUrl(buf, sizeof(buf)));
}
}
#endif
=== modified file 'src/security/PeerOptions.cc'
--- src/security/PeerOptions.cc 2016-05-21 23:19:36 +0000
+++ src/security/PeerOptions.cc 2016-05-25 05:28:36 +0000
@@ -223,64 +223,58 @@
#if USE_OPENSSL
Ssl::Initialize();
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
t = SSL_CTX_new(TLS_client_method());
#else
t = SSL_CTX_new(SSLv23_client_method());
#endif
if (!t) {
const auto x = ERR_error_string(ERR_get_error(), nullptr);
fatalf("Failed to allocate TLS client context: %s\n", x);
}
#elif USE_GNUTLS
// Initialize for X.509 certificate exchange
if (const int x = gnutls_certificate_allocate_credentials(&t)) {
fatalf("Failed to allocate TLS client context: error=%d\n", x);
}
#else
- fatal("Failed to allocate TLS client context: No TLS library\n");
+ debugs(83, 1, "WARNING: Failed to allocate TLS client context: No TLS library");
#endif
return t;
}
Security::ContextPtr
Security::PeerOptions::createClientContext(bool setOptions)
{
- Security::ContextPtr t = nullptr;
-
updateTlsVersionLimits();
+ Security::ContextPtr t = createBlankContext();
+ if (t) {
#if USE_OPENSSL
- // XXX: temporary performance regression. c_str() data copies and prevents this being a const method
- t = sslCreateClientContext(*this, (setOptions ? parsedOptions : 0), parsedFlags);
-
-#elif USE_GNUTLS && WHEN_READY_FOR_GNUTLS
- t = createBlankContext();
-
+ // XXX: temporary performance regression. c_str() data copies and prevents this being a const method
+ Ssl::InitClientContext(t, *this, (setOptions ? parsedOptions : 0), parsedFlags);
#endif
-
- if (t) {
updateContextNpn(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
=== modified file 'src/security/ServerOptions.cc'
--- src/security/ServerOptions.cc 2016-04-11 16:34:29 +0000
+++ src/security/ServerOptions.cc 2016-05-25 05:28:08 +0000
@@ -100,40 +100,55 @@
#endif
if (!t) {
const auto x = ERR_error_string(ERR_get_error(), nullptr);
debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: " << x);
}
#elif USE_GNUTLS
// Initialize for X.509 certificate exchange
if (const int x = gnutls_certificate_allocate_credentials(&t)) {
debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: error=" << x);
}
#else
debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: No TLS library");
#endif
return t;
}
+Security::ContextPtr
+Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &port)
+{
+ updateTlsVersionLimits();
+
+ Security::ContextPtr t = createBlankContext();
+ if (t) {
+#if USE_OPENSSL
+ Ssl::InitServerContext(t, port);
+#endif
+ }
+
+ return t;
+}
+
void
Security::ServerOptions::loadDhParams()
{
if (dhParamsFile.isEmpty())
return;
#if USE_OPENSSL
DH *dhp = nullptr;
if (FILE *in = fopen(dhParamsFile.c_str(), "r")) {
dhp = PEM_read_DHparams(in, NULL, NULL, NULL);
fclose(in);
}
if (!dhp) {
debugs(83, DBG_IMPORTANT, "WARNING: Failed to read DH parameters '" << dhParamsFile << "'");
return;
}
int codes;
if (DH_check(dhp, &codes) == 0) {
=== modified file 'src/security/ServerOptions.h'
--- src/security/ServerOptions.h 2016-04-11 16:34:29 +0000
+++ src/security/ServerOptions.h 2016-05-25 10:38:53 +0000
@@ -1,53 +1,57 @@
/*
* Copyright (C) 1996-2016 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
* Please see the COPYING and CONTRIBUTORS files for details.
*/
#ifndef SQUID_SRC_SECURITY_SERVEROPTIONS_H
#define SQUID_SRC_SECURITY_SERVEROPTIONS_H
+#include "anyp/forward.h"
#include "security/PeerOptions.h"
namespace Security
{
/// TLS squid.conf settings for a listening port
class ServerOptions : public PeerOptions
{
public:
ServerOptions() : PeerOptions() {
// Bug 4005: dynamic contexts use a lot of memory and it
// is more secure to have only a small set of trusted CA.
flags.tlsDefaultCa.defaultTo(false);
}
virtual ~ServerOptions() = default;
/* Security::PeerOptions API */
virtual void parse(const char *);
virtual void clear() {*this = ServerOptions();}
virtual Security::ContextPtr createBlankContext() const;
virtual void dumpCfg(Packable *, const char *pfx) const;
+ /// generate a security server-context from these configured options
+ Security::ContextPtr createStaticServerContext(AnyP::PortCfg &);
+
/// update the context with DH, EDH, EECDH settings
void updateContextEecdh(Security::ContextPtr &);
public:
/// TLS context to use for HTTPS accelerator or static SSL-Bump
Security::ContextPointer staticContext;
private:
void loadDhParams();
private:
SBuf dh; ///< Diffi-Helman cipher config
SBuf dhParamsFile; ///< Diffi-Helman ciphers parameter file
SBuf eecdhCurve; ///< Elliptic curve for ephemeral EC-based DH key exchanges
Security::DhePointer parsedDhParams; ///< DH parameters for temporary/ephemeral DH key exchanges
};
} // namespace Security
=== modified file 'src/ssl/support.cc'
--- src/ssl/support.cc 2016-05-20 13:20:27 +0000
+++ src/ssl/support.cc 2016-05-25 05:26:44 +0000
@@ -539,111 +539,109 @@
} 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);
} else {
debugs(83, 9, "Not requiring any client certificates");
SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
}
if (port.secure.parsedFlags & SSL_FLAG_DONT_VERIFY_DOMAIN)
SSL_CTX_set_ex_data(sslContext, ssl_ctx_ex_index_dont_verify_domain, (void *) -1);
Ssl::SetSessionCallbacks(sslContext);
return true;
}
-Security::ContextPtr
-sslCreateServerContext(AnyP::PortCfg &port)
+bool
+Ssl::InitServerContext(Security::ContextPtr &sslContext, AnyP::PortCfg &port)
{
- Security::ContextPtr sslContext(port.secure.createBlankContext());
if (!sslContext)
- return nullptr;
+ return false;
if (!SSL_CTX_use_certificate(sslContext, port.signingCert.get())) {
const int ssl_error = ERR_get_error();
const auto &keys = port.secure.certs.front();
debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS certificate '" << keys.certFile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
if (!SSL_CTX_use_PrivateKey(sslContext, port.signPkey.get())) {
const int ssl_error = ERR_get_error();
const auto &keys = port.secure.certs.front();
debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS private key '" << keys.privateKeyFile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
Ssl::addChainToSslContext(sslContext, port.certsToChain.get());
/* Alternate code;
debugs(83, DBG_IMPORTANT, "Using certificate in " << certfile);
if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) {
ssl_error = ERR_get_error();
debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
debugs(83, DBG_IMPORTANT, "Using private key in " << keyfile);
ssl_ask_password(sslContext, keyfile);
if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) {
ssl_error = ERR_get_error();
debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
debugs(83, 5, "Comparing private and public SSL keys.");
if (!SSL_CTX_check_private_key(sslContext)) {
ssl_error = ERR_get_error();
debugs(83, DBG_CRITICAL, "ERROR: SSL private key '" << certfile << "' does not match public key '" <<
keyfile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
*/
if (!configureSslContext(sslContext, port)) {
debugs(83, DBG_CRITICAL, "ERROR: Configuring static SSL context");
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
- return sslContext;
+ return true;
}
-Security::ContextPtr
-sslCreateClientContext(Security::PeerOptions &peer, long options, long fl)
+bool
+Ssl::InitClientContext(Security::ContextPtr &sslContext, Security::PeerOptions &peer, long options, long fl)
{
- Security::ContextPtr sslContext(peer.createBlankContext());
if (!sslContext)
- return nullptr;
+ return false;
SSL_CTX_set_options(sslContext, options);
#if defined(SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
SSL_CTX_set_info_callback(sslContext, ssl_info_cb);
#endif
if (!peer.sslCipher.isEmpty()) {
debugs(83, 5, "Using chiper suite " << peer.sslCipher << ".");
const char *cipher = peer.sslCipher.c_str();
if (!SSL_CTX_set_cipher_list(sslContext, cipher)) {
const int ssl_error = ERR_get_error();
fatalf("Failed to set SSL cipher suite '%s': %s\n",
cipher, ERR_error_string(ssl_error, NULL));
}
}
if (!peer.certs.empty()) {
// TODO: support loading multiple cert/key pairs
@@ -672,41 +670,41 @@
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);
}
- return sslContext;
+ return true;
}
/// \ingroup ServerProtocolSSLInternal
int
ssl_read_method(int fd, char *buf, int len)
{
auto ssl = fd_table[fd].ssl.get();
#if DONT_DO_THIS
if (!SSL_is_init_finished(ssl)) {
errno = ENOTCONN;
return -1;
}
#endif
int i = SSL_read(ssl, buf, len);
if (i > 0 && SSL_pending(ssl) > 0) {
=== modified file 'src/ssl/support.h'
--- src/ssl/support.h 2016-04-05 09:43:47 +0000
+++ src/ssl/support.h 2016-05-25 05:26:01 +0000
@@ -94,47 +94,47 @@
/**
* Absolute cert position in the final certificate chain that may include
* intermediate certificates. Chain positions start with zero and increase
* towards the root certificate. Negative if unknown.
*/
int depth;
CertError(ssl_error_t anErr, X509 *aCert, int depth = -1);
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;
void SetSessionCallbacks(Security::ContextPtr);
extern Ipc::MemMap *SessionCache;
extern const char *SessionCacheName;
-} //namespace Ssl
+/// initialize a TLS server context with OpenSSL specific settings
+bool InitServerContext(Security::ContextPtr &, AnyP::PortCfg &);
-/// \ingroup ServerProtocolSSLAPI
-Security::ContextPtr sslCreateServerContext(AnyP::PortCfg &port);
+/// initialize a TLS client context with OpenSSL specific settings
+bool InitClientContext(Security::ContextPtr &, Security::PeerOptions &, long options, long flags);
-/// \ingroup ServerProtocolSSLAPI
-Security::ContextPtr sslCreateClientContext(Security::PeerOptions &, long options, long flags);
+} //namespace Ssl
/// \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_libsslsquid.cc'
--- src/tests/stub_libsslsquid.cc 2016-02-17 21:03:29 +0000
+++ src/tests/stub_libsslsquid.cc 2016-05-25 05:27:22 +0000
@@ -38,43 +38,43 @@
Ssl::LocalContextStorage *Ssl::GlobalContextStorage::getLocalStorage(Ip::Address const & address)
{ fatal(STUB_API " required"); static Ssl::LocalContextStorage v(0,0); return &v; }
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)
+bool InitServerContext(Security::ContextPtr &, AnyP::PortCfg &) STUB_RETVAL(false)
+bool InitClientContext(Security::ContextPtr &, Security::PeerOptions &, long, const char *) STUB_RETVAL(false)
} // namespace Ssl
-Security::ContextPtr sslCreateServerContext(AnyP::PortCfg &port) STUB_RETVAL(NULL)
-Security::ContextPtr sslCreateClientContext(Security::PeerOptions &, long, const char *) STUB_RETVAL(nullptr)
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[] = {""};
bool generateUntrustedCert(Security::CertPointer & untrustedCert, EVP_PKEY_Pointer & untrustedPkey, Security::CertPointer const & cert, EVP_PKEY_Pointer const & pkey) STUB_RETVAL(false)
Security::ContextPtr generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port) STUB_RETVAL(NULL)
bool verifySslCertificate(Security::ContextPtr sslContext, CertificateProperties const &properties) STUB_RETVAL(false)
Security::ContextPtr generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port) STUB_RETVAL(NULL)
void addChainToSslContext(Security::ContextPtr sslContext, STACK_OF(X509) *certList) STUB
void readCertChainAndPrivateKeyFromFiles(Security::CertPointer & cert, EVP_PKEY_Pointer & pkey, X509_STACK_Pointer & chain, char const * certFilename, char const * keyFilename) STUB
More information about the squid-dev
mailing list