The attached patch fixes two problems
- Bug 3868: The SSL_CTX_new in newer openSSL releases requires a const
'SSL_METHOD *' argument and in older releases requires non const
'SSL_METHD *' argument. Currently we are trying to identify openSSL
version using the OPENSSL_VERSION_NUMBER define but looks that
sometimes we are failing to correctly identify the cases.
- sk_OPENSSL_PSTRING_value is buggy in early openSSL-1.0.0? releases
causing compile errors in squid. Also see the "compiling errors on
squid3 head 919" thread in squid-dev mailing list.
I tried to compile it using various openSSL versions. I hope it is OK
and fixes the above problems.
=== modified file 'acinclude/lib-checks.m4'
--- acinclude/lib-checks.m4 2013-05-15 15:56:40 +0000
+++ acinclude/lib-checks.m4 2013-06-29 11:52:57 +0000
@@ -142,74 +142,131 @@
SSL_CTX *sslContext = SSL_CTX_new(SSLv3_method());
X509 ***pCert = (X509 ***)sslContext->cert;
X509 *sslCtxCert = pCert && *pCert ? **pCert : (X509 *)0x1;
if (sslCtxCert != NULL)
return 1;
return 0;
])
],
[
AC_MSG_RESULT([yes])
AC_DEFINE(SQUID_USE_SSLGETCERTIFICATE_HACK, 1)
],
[
AC_MSG_RESULT([no])
],
[])
SQUID_STATE_ROLLBACK(check_SSL_get_certificate)
])
+dnl Checks whether the SSL_CTX_new and similar functions require
+dnl a const 'SSL_METHOD *' argument
+AC_DEFUN([SQUID_CHECK_OPENSSL_CONST_SSL_METHOD],[
+ AH_TEMPLATE(SQUID_USE_CONST_SSL_METHOD, "Define to 1 if the SSL_CTX_new and similar openSSL API functions require 'const SSL_METHOD *'")
+ SQUID_STATE_SAVE(check_const_SSL_METHOD)
+ AC_MSG_CHECKING(whether SSL_CTX_new and similar openSSL API functions require 'const SSL_METHOD *'")
+
+ AC_COMPILE_IFELSE([
+ AC_LANG_PROGRAM(
+ [
+ #include <openssl/ssl.h>
+ #include <openssl/err.h>
+ ],
+ [
+ const SSL_METHOD *method = NULL;
+ SSL_CTX *sslContext = SSL_CTX_new(method);
+ return (sslContext != NULL);
+ ])
+ ],
+ [
+ AC_DEFINE(SQUID_USE_CONST_SSL_METHOD, 1)
+ AC_MSG_RESULT([yes])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ],
+ [])
+
+SQUID_STATE_ROLLBACK(check_const_SSL_METHOD)
+]
+)
dnl Try to handle TXT_DB related problems:
dnl 1) The type of TXT_DB::data member changed in openSSL-1.0.1 version
dnl 2) The IMPLEMENT_LHASH_* openSSL macros in openSSL-1.0.1 and later releases is not
dnl implemented correctly and causes type conversion errors while compiling squid
AC_DEFUN([SQUID_CHECK_OPENSSL_TXTDB],[
AH_TEMPLATE(SQUID_SSLTXTDB_PSTRINGDATA, "Define to 1 if the TXT_DB uses OPENSSL_PSTRING data member")
+ AH_TEMPLATE(SQUID_STACKOF_PSTRINGDATA_HACK, "Define to 1 to use squid workaround for buggy versions of sk_OPENSSL_PSTRING_value")
AH_TEMPLATE(SQUID_USE_SSLLHASH_HACK, "Define to 1 to use squid workaround for openssl IMPLEMENT_LHASH_* type conversion errors")
SQUID_STATE_SAVE(check_TXTDB)
LIBS="$LIBS $SSLLIB"
+ squid_cv_check_openssl_pstring="no"
AC_MSG_CHECKING(whether the TXT_DB use OPENSSL_PSTRING data member)
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM(
[
#include <openssl/txt_db.h>
],
[
TXT_DB *db = NULL;
int i = sk_OPENSSL_PSTRING_num(db->data);
return 0;
])
],
[
AC_DEFINE(SQUID_SSLTXTDB_PSTRINGDATA, 1)
AC_MSG_RESULT([yes])
+ squid_cv_check_openssl_pstring="yes"
],
[
AC_MSG_RESULT([no])
],
[])
+ if test x"$squid_cv_check_openssl_pstring" = "xyes"; then
+ AC_MSG_CHECKING(whether the squid workaround for buggy versions of sk_OPENSSL_PSTRING_value should used)
+ AC_COMPILE_IFELSE([
+ AC_LANG_PROGRAM(
+ [
+ #include <openssl/txt_db.h>
+ ],
+ [
+ TXT_DB *db = NULL;
+ const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db->data, 0));
+ return (current_row != NULL);
+ ])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ],
+ [
+ AC_DEFINE(SQUID_STACKOF_PSTRINGDATA_HACK, 1)
+ AC_MSG_RESULT([yes])
+ ],
+ [])
+ fi
+
AC_MSG_CHECKING(whether the workaround for OpenSSL IMPLEMENT_LHASH_ macros should used)
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM(
[
#include <openssl/txt_db.h>
static unsigned long index_serial_hash(const char **a){}
static int index_serial_cmp(const char **a, const char **b){}
static IMPLEMENT_LHASH_HASH_FN(index_serial_hash,const char **)
static IMPLEMENT_LHASH_COMP_FN(index_serial_cmp,const char **)
],
[
TXT_DB *db = NULL;
TXT_DB_create_index(db, 1, NULL, LHASH_HASH_FN(index_serial_hash), LHASH_COMP_FN(index_serial_cmp));
])
],
[
AC_MSG_RESULT([no])
],
[
=== modified file 'configure.ac'
--- configure.ac 2013-06-11 15:16:07 +0000
+++ configure.ac 2013-06-29 11:55:25 +0000
@@ -1260,40 +1260,41 @@
SQUID_DEFINE_BOOL(USE_OPENSSL,${with_openssl},
[Define this to make use of the OpenSSL libraries for MD5 calculation rather than Squid-supplied MD5 implementation or if building with SSL encryption])
if test "x$enable_ssl" = "xyes"; then
if test "x$SSLLIB" = "x"; then
SSLLIB="-lcrypto" # for MD5 routines
fi
# This is a workaround for RedHat 9 brain damage..
if test -d /usr/kerberos/include -a "x$SSLLIBDIR" = "x" -a -f /usr/include/openssl/kssl.h; then
AC_MSG_NOTICE([OpenSSL depends on Kerberos])
SSLLIBDIR="/usr/kerberos/lib"
CPPFLAGS="$CPPFLAGS -I/usr/kerberos/include"
fi
fi
if test "x$SSLLIBDIR" != "x" ; then
SSLLIB="-L$SSLLIBDIR $SSLLIB"
fi
AC_SUBST(SSLLIB)
if test "x$with_openssl" = "xyes"; then
SQUID_CHECK_OPENSSL_GETCERTIFICATE_WORKS
+SQUID_CHECK_OPENSSL_CONST_SSL_METHOD
SQUID_CHECK_OPENSSL_TXTDB
fi
AC_ARG_ENABLE(forw-via-db,
AS_HELP_STRING([--enable-forw-via-db],[Enable Forw/Via database]), [
SQUID_YESNO([$enableval],[unrecognized argument to --enable-forw-via-db: $enableval])
])
SQUID_DEFINE_BOOL(USE_FORW_VIA_DB,${enable_forw_via_db:=no},
[Enable Forw/Via database])
AC_MSG_NOTICE([Forw/Via database enabled: $enable_forw_via_db])
AC_ARG_ENABLE(cache-digests,
AS_HELP_STRING([--enable-cache-digests],
[Use Cache Digests. See http://wiki.squid-cache.org/SquidFaq/CacheDigests]),
[
SQUID_YESNO($enableval,
[unrecognized argument to --enable-cache-digests: $enableval])
])
SQUID_DEFINE_BOOL(USE_CACHE_DIGESTS,${enable_cache_digests:=no},
[Use Cache Digests for locating objects in neighbor caches.])
=== modified file 'src/ssl/certificate_db.cc'
--- src/ssl/certificate_db.cc 2013-05-15 15:41:43 +0000
+++ src/ssl/certificate_db.cc 2013-06-29 12:34:52 +0000
@@ -150,41 +150,45 @@
}
if (value) {
row[cell] = static_cast<char *>(OPENSSL_malloc(sizeof(char) * (strlen(value) + 1)));
memcpy(row[cell], value, sizeof(char) * (strlen(value) + 1));
} else
row[cell] = NULL;
}
char ** Ssl::CertificateDb::Row::getRow()
{
return row;
}
void Ssl::CertificateDb::sq_TXT_DB_delete(TXT_DB *db, const char **row)
{
if (!db)
return;
#if SQUID_SSLTXTDB_PSTRINGDATA
for (int i = 0; i < sk_OPENSSL_PSTRING_num(db->data); ++i) {
+#if SQUID_STACKOF_PSTRINGDATA_HACK
+ const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db->data), i));
+#else
const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db->data, i));
+#endif
#else
for (int i = 0; i < sk_num(db->data); ++i) {
const char ** current_row = ((const char **)sk_value(db->data, i));
#endif
if (current_row == row) {
sq_TXT_DB_delete_row(db, i);
return;
}
}
}
#define countof(arr) (sizeof(arr)/sizeof(*arr))
void Ssl::CertificateDb::sq_TXT_DB_delete_row(TXT_DB *db, int idx)
{
char **rrow;
#if SQUID_SSLTXTDB_PSTRINGDATA
rrow = (char **)sk_OPENSSL_PSTRING_delete(db->data, idx);
#else
rrow = (char **)sk_delete(db->data, idx);
#endif
@@ -500,85 +504,97 @@
// Normally defined in defines.h file
void Ssl::CertificateDb::deleteRow(const char **row, int rowIndex)
{
const std::string filename(cert_full + "/" + row[cnlSerial] + ".pem");
sq_TXT_DB_delete_row(db.get(), rowIndex);
subSize(filename);
int ret = remove(filename.c_str());
if (ret < 0 && errno != ENOENT)
throw std::runtime_error("Failed to remove certficate file " + filename + " from db");
}
bool Ssl::CertificateDb::deleteInvalidCertificate()
{
if (!db)
return false;
bool removed_one = false;
#if SQUID_SSLTXTDB_PSTRINGDATA
for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); ++i) {
+#if SQUID_STACKOF_PSTRINGDATA_HACK
+ const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), i));
+#else
const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db.get()->data, i));
+#endif
#else
for (int i = 0; i < sk_num(db.get()->data); ++i) {
const char ** current_row = ((const char **)sk_value(db.get()->data, i));
#endif
if (!sslDateIsInTheFuture(current_row[cnlExp_date])) {
deleteRow(current_row, i);
removed_one = true;
break;
}
}
if (!removed_one)
return false;
return true;
}
bool Ssl::CertificateDb::deleteOldestCertificate()
{
if (!db)
return false;
#if SQUID_SSLTXTDB_PSTRINGDATA
if (sk_OPENSSL_PSTRING_num(db.get()->data) == 0)
#else
if (sk_num(db.get()->data) == 0)
#endif
return false;
#if SQUID_SSLTXTDB_PSTRINGDATA
+#if SQUID_STACKOF_PSTRINGDATA_HACK
+ const char **row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), 0));
+#else
const char **row = (const char **)sk_OPENSSL_PSTRING_value(db.get()->data, 0);
+#endif
#else
const char **row = (const char **)sk_value(db.get()->data, 0);
#endif
deleteRow(row, 0);
return true;
}
bool Ssl::CertificateDb::deleteByHostname(std::string const & host)
{
if (!db)
return false;
#if SQUID_SSLTXTDB_PSTRINGDATA
for (int i = 0; i < sk_OPENSSL_PSTRING_num(db.get()->data); ++i) {
+#if SQUID_STACKOF_PSTRINGDATA_HACK
+ const char ** current_row = ((const char **)sk_value(CHECKED_STACK_OF(OPENSSL_PSTRING, db.get()->data), i));
+#else
const char ** current_row = ((const char **)sk_OPENSSL_PSTRING_value(db.get()->data, i));
+#endif
#else
for (int i = 0; i < sk_num(db.get()->data); ++i) {
const char ** current_row = ((const char **)sk_value(db.get()->data, i));
#endif
if (host == current_row[cnlName]) {
deleteRow(current_row, i);
return true;
}
}
return false;
}
bool Ssl::CertificateDb::IsEnabledDiskStore() const
{
return enabled_disk_store;
}
=== modified file 'src/ssl/gadgets.h'
--- src/ssl/gadgets.h 2012-09-06 13:12:26 +0000
+++ src/ssl/gadgets.h 2013-06-29 12:00:59 +0000
@@ -9,44 +9,44 @@
#include "ssl/crtd_message.h"
#if HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
#endif
#if HAVE_OPENSSL_TXT_DB_H
#include <openssl/txt_db.h>
#endif
#if HAVE_STRING
#include <string>
#endif
namespace Ssl
{
/**
\defgroup SslCrtdSslAPI ssl_crtd SSL api.
These functions must not depend on Squid runtime code such as debug()
because they are used by ssl_crtd.
*/
-#if OPENSSL_VERSION_NUMBER < 0x00909000L
-typedef SSL_METHOD * ContextMethod;
-#else
+#if SQUID_USE_CONST_SSL_METHOD
typedef const SSL_METHOD * ContextMethod;
+#else
+typedef SSL_METHOD * ContextMethod;
#endif
/**
\ingroup SslCrtdSslAPI
* Add SSL locking (a.k.a. reference counting) to TidyPointer
*/
template <typename T, void (*DeAllocator)(T *t), int lock>
class LockingPointer: public TidyPointer<T, DeAllocator>
{
public:
typedef TidyPointer<T, DeAllocator> Parent;
LockingPointer(T *t = NULL): Parent(t) {
}
void resetAndLock(T *t) {
if (t != this->get()) {
this->reset(t);
if (t)
CRYPTO_add(&t->references, 1, lock);
=== modified file 'src/ssl/support.cc'
--- src/ssl/support.cc 2013-06-18 10:23:41 +0000
+++ src/ssl/support.cc 2013-06-29 12:01:52 +0000
@@ -954,46 +954,42 @@
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;
}
*/
if (!configureSslContext(sslContext, port)) {
debugs(83, DBG_CRITICAL, "ERROR: Configuring static SSL context");
SSL_CTX_free(sslContext);
return NULL;
}
return sslContext;
}
SSL_CTX *
sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile)
{
int ssl_error;
-#if OPENSSL_VERSION_NUMBER < 0x00909000L
- SSL_METHOD *method;
-#else
- const SSL_METHOD *method;
-#endif
- SSL_CTX *sslContext;
+ Ssl::ContextMethod method;
+ SSL_CTX * sslContext;
long fl = Ssl::parse_flags(flags);
ssl_initialize();
if (!keyfile)
keyfile = certfile;
if (!certfile)
certfile = keyfile;
switch (version) {
case 2:
#ifndef OPENSSL_NO_SSL2
debugs(83, 5, "Using SSLv2.");
method = SSLv2_client_method();
#else
debugs(83, DBG_IMPORTANT, "SSLv2 is not available in this Proxy.");
return NULL;
#endif