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

Reply via email to