Re: [HACKERS] OpenSSL 1.1 breaks configure and more - Mailing list pgsql-hackers

From Tom Lane
Subject Re: [HACKERS] OpenSSL 1.1 breaks configure and more
Date
Msg-id 20047.1492305247@sss.pgh.pa.us
Whole thread Raw
In response to Re: OpenSSL 1.1 breaks configure and more  (Andreas Karlsson <andreas@proxel.se>)
Responses Re: [HACKERS] OpenSSL 1.1 breaks configure and more  (Tom Lane <tgl@sss.pgh.pa.us>)
Re: [HACKERS] OpenSSL 1.1 breaks configure and more  (Andreas Karlsson <andreas@proxel.se>)
List pgsql-hackers
Andreas Karlsson <andreas@proxel.se> writes:
> On 09/15/2016 05:38 PM, Alvaro Herrera wrote:
>> I suppose some interested party could grab the patch that Heikki
>> committed to the new branches and produce a back-patch that can be
>> applied to the older branches.

> Here is the result of backporting the sum of the two patches on top of 
> REL9_4_STABLE. Not sure if we need this, but if we do we can apply this 
> patch.

I've pushed this into 9.4 with trivial corrections (fix merge failure
against a later patch, and sync the autoconf output files with the
actual contents of configure.in).  I've tested it locally against
openssl 1.0.1e and 1.1.0e, but not anything older.  What I did to test
was to copy the 9.5-branch src/test/ssl/ stuff into 9.4 and run it.
I saw failures on the tests for Subject Alternative Name, which is
unsurprising since we added that support as a feature in 9.5, but
everything else passed.  Unless the buildfarm turns up problems,
I think we're ok there.

I tried to push the code into 9.3, and saw the same problems Christoph
mentioned for 9.2: it compiles fine against 1.0.1e, but the references
to port->ssl->state don't work with 1.1.  The reason that's OK in 9.4
is not that we removed SSL negotiation; that didn't happen until 9.5.
Rather, it's because this 9.4 commit got rid of the bogus code:

Author: Alvaro Herrera <alvherre@alvh.no-ip.org>
Branch: master Release: REL9_4_BR [31cf1a1a4] 2013-10-10 23:45:20 -0300

    Rework SSL renegotiation code

If we want to go any further back with 1.1 support, we have a range
of options:

1. Back-patch that patch, probably also including the followup adjustments
  in 86029b31e and 36a3be654.

2. Add #if's to use 31cf1a1a4's coding with OpenSSL >= 1.1, while keeping
   the older code for use when built against older OpenSSLs.

3. Conditionally disable renegotiation altogether with OpenSSL >= 1.1,
   thus adopting 9.5 not 9.4 behavior when using newer OpenSSL.

I think #3 would be fairly weird unless we also changed 9.4 similarly.
But there's some argument for doing that: we don't really have any field
experience with using renegotiation with OpenSSL 1.1, so we don't know
that what is in the 9.4 branch right now actually works with 1.1.
On the other hand, it would also be the most work of these options,
since we'd have to do things like adding conditional behavior in guc.c.

Thoughts?

For the archives' sake, attached is the 9.3-adapted version of the
patch so far.

            regards, tom lane

diff --git a/configure b/configure
index 0702667..e548722 100755
*** a/configure
--- b/configure
*************** $as_echo "$as_me: error: library 'crypto
*** 9524,9532 ****
  fi


! { $as_echo "$as_me:$LINENO: checking for SSL_library_init in -lssl" >&5
! $as_echo_n "checking for SSL_library_init in -lssl... " >&6; }
! if test "${ac_cv_lib_ssl_SSL_library_init+set}" = set; then
    $as_echo_n "(cached) " >&6
  else
    ac_check_lib_save_LIBS=$LIBS
--- 9524,9532 ----
  fi


! { $as_echo "$as_me:$LINENO: checking for SSL_new in -lssl" >&5
! $as_echo_n "checking for SSL_new in -lssl... " >&6; }
! if test "${ac_cv_lib_ssl_SSL_new+set}" = set; then
    $as_echo_n "(cached) " >&6
  else
    ac_check_lib_save_LIBS=$LIBS
*************** cat >>conftest.$ac_ext <<_ACEOF
*** 9544,9554 ****
  #ifdef __cplusplus
  extern "C"
  #endif
! char SSL_library_init ();
  int
  main ()
  {
! return SSL_library_init ();
    ;
    return 0;
  }
--- 9544,9554 ----
  #ifdef __cplusplus
  extern "C"
  #endif
! char SSL_new ();
  int
  main ()
  {
! return SSL_new ();
    ;
    return 0;
  }
*************** $as_echo "$ac_try_echo") >&5
*** 9574,9585 ****
       test "$cross_compiling" = yes ||
       $as_test_x conftest$ac_exeext
         }; then
!   ac_cv_lib_ssl_SSL_library_init=yes
  else
    $as_echo "$as_me: failed program was:" >&5
  sed 's/^/| /' conftest.$ac_ext >&5

!     ac_cv_lib_ssl_SSL_library_init=no
  fi

  rm -rf conftest.dSYM
--- 9574,9585 ----
       test "$cross_compiling" = yes ||
       $as_test_x conftest$ac_exeext
         }; then
!   ac_cv_lib_ssl_SSL_new=yes
  else
    $as_echo "$as_me: failed program was:" >&5
  sed 's/^/| /' conftest.$ac_ext >&5

!     ac_cv_lib_ssl_SSL_new=no
  fi

  rm -rf conftest.dSYM
*************** rm -f core conftest.err conftest.$ac_obj
*** 9587,9595 ****
        conftest$ac_exeext conftest.$ac_ext
  LIBS=$ac_check_lib_save_LIBS
  fi
! { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_SSL_library_init" >&5
! $as_echo "$ac_cv_lib_ssl_SSL_library_init" >&6; }
! if test "x$ac_cv_lib_ssl_SSL_library_init" = x""yes; then
    cat >>confdefs.h <<_ACEOF
  #define HAVE_LIBSSL 1
  _ACEOF
--- 9587,9595 ----
        conftest$ac_exeext conftest.$ac_ext
  LIBS=$ac_check_lib_save_LIBS
  fi
! { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ssl_SSL_new" >&5
! $as_echo "$ac_cv_lib_ssl_SSL_new" >&6; }
! if test "x$ac_cv_lib_ssl_SSL_new" = x""yes; then
    cat >>confdefs.h <<_ACEOF
  #define HAVE_LIBSSL 1
  _ACEOF
*************** $as_echo "$as_me: error: library 'eay32'
*** 9694,9702 ****
     { (exit 1); exit 1; }; }
  fi

!      { $as_echo "$as_me:$LINENO: checking for library containing SSL_library_init" >&5
! $as_echo_n "checking for library containing SSL_library_init... " >&6; }
! if test "${ac_cv_search_SSL_library_init+set}" = set; then
    $as_echo_n "(cached) " >&6
  else
    ac_func_search_save_LIBS=$LIBS
--- 9694,9702 ----
     { (exit 1); exit 1; }; }
  fi

!      { $as_echo "$as_me:$LINENO: checking for library containing SSL_new" >&5
! $as_echo_n "checking for library containing SSL_new... " >&6; }
! if test "${ac_cv_search_SSL_new+set}" = set; then
    $as_echo_n "(cached) " >&6
  else
    ac_func_search_save_LIBS=$LIBS
*************** cat >>conftest.$ac_ext <<_ACEOF
*** 9713,9723 ****
  #ifdef __cplusplus
  extern "C"
  #endif
! char SSL_library_init ();
  int
  main ()
  {
! return SSL_library_init ();
    ;
    return 0;
  }
--- 9713,9723 ----
  #ifdef __cplusplus
  extern "C"
  #endif
! char SSL_new ();
  int
  main ()
  {
! return SSL_new ();
    ;
    return 0;
  }
*************** $as_echo "$ac_try_echo") >&5
*** 9750,9756 ****
       test "$cross_compiling" = yes ||
       $as_test_x conftest$ac_exeext
         }; then
!   ac_cv_search_SSL_library_init=$ac_res
  else
    $as_echo "$as_me: failed program was:" >&5
  sed 's/^/| /' conftest.$ac_ext >&5
--- 9750,9756 ----
       test "$cross_compiling" = yes ||
       $as_test_x conftest$ac_exeext
         }; then
!   ac_cv_search_SSL_new=$ac_res
  else
    $as_echo "$as_me: failed program was:" >&5
  sed 's/^/| /' conftest.$ac_ext >&5
*************** fi
*** 9761,9781 ****
  rm -rf conftest.dSYM
  rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
        conftest$ac_exeext
!   if test "${ac_cv_search_SSL_library_init+set}" = set; then
    break
  fi
  done
! if test "${ac_cv_search_SSL_library_init+set}" = set; then
    :
  else
!   ac_cv_search_SSL_library_init=no
  fi
  rm conftest.$ac_ext
  LIBS=$ac_func_search_save_LIBS
  fi
! { $as_echo "$as_me:$LINENO: result: $ac_cv_search_SSL_library_init" >&5
! $as_echo "$ac_cv_search_SSL_library_init" >&6; }
! ac_res=$ac_cv_search_SSL_library_init
  if test "$ac_res" != no; then
    test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"

--- 9761,9781 ----
  rm -rf conftest.dSYM
  rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
        conftest$ac_exeext
!   if test "${ac_cv_search_SSL_new+set}" = set; then
    break
  fi
  done
! if test "${ac_cv_search_SSL_new+set}" = set; then
    :
  else
!   ac_cv_search_SSL_new=no
  fi
  rm conftest.$ac_ext
  LIBS=$ac_func_search_save_LIBS
  fi
! { $as_echo "$as_me:$LINENO: result: $ac_cv_search_SSL_new" >&5
! $as_echo "$ac_cv_search_SSL_new" >&6; }
! ac_res=$ac_cv_search_SSL_new
  if test "$ac_res" != no; then
    test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"

*************** $as_echo "$as_me: error: library 'ssleay
*** 9786,9791 ****
--- 9786,10004 ----
  fi

    fi
+   # Functions introduced in OpenSSL 1.1.0. We used to check for
+   # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
+   # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
+   # doesn't have these OpenSSL 1.1.0 functions. So check for individual
+   # functions.
+
+
+
+
+ for ac_func in OPENSSL_init_ssl BIO_meth_new ASN1_STRING_get0_data RAND_OpenSSL
+ do
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
+ $as_echo_n "checking for $ac_func... " >&6; }
+ if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+   $as_echo_n "(cached) " >&6
+ else
+   cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h.  */
+ _ACEOF
+ cat confdefs.h >>conftest.$ac_ext
+ cat >>conftest.$ac_ext <<_ACEOF
+ /* end confdefs.h.  */
+ /* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+    For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+ #define $ac_func innocuous_$ac_func
+
+ /* System header to define __stub macros and hopefully few prototypes,
+     which can conflict with char $ac_func (); below.
+     Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+     <limits.h> exists even on freestanding compilers.  */
+
+ #ifdef __STDC__
+ # include <limits.h>
+ #else
+ # include <assert.h>
+ #endif
+
+ #undef $ac_func
+
+ /* Override any GCC internal prototype to avoid an error.
+    Use char because int might match the return type of a GCC
+    builtin and then its argument prototype would still apply.  */
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+ char $ac_func ();
+ /* The GNU C library defines this for functions which it implements
+     to always fail with ENOSYS.  Some functions are actually named
+     something starting with __ and the normal name is an alias.  */
+ #if defined __stub_$ac_func || defined __stub___$ac_func
+ choke me
+ #endif
+
+ int
+ main ()
+ {
+ return $ac_func ();
+   ;
+   return 0;
+ }
+ _ACEOF
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { (ac_try="$ac_link"
+ case "(($ac_try" in
+   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+   *) ac_try_echo=$ac_try;;
+ esac
+ eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+ $as_echo "$ac_try_echo") >&5
+   (eval "$ac_link") 2>conftest.er1
+   ac_status=$?
+   grep -v '^ *+' conftest.er1 >conftest.err
+   rm -f conftest.er1
+   cat conftest.err >&5
+   $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } && {
+      test -z "$ac_c_werror_flag" ||
+      test ! -s conftest.err
+        } && test -s conftest$ac_exeext && {
+      test "$cross_compiling" = yes ||
+      $as_test_x conftest$ac_exeext
+        }; then
+   eval "$as_ac_var=yes"
+ else
+   $as_echo "$as_me: failed program was:" >&5
+ sed 's/^/| /' conftest.$ac_ext >&5
+
+     eval "$as_ac_var=no"
+ fi
+
+ rm -rf conftest.dSYM
+ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+       conftest$ac_exeext conftest.$ac_ext
+ fi
+ ac_res=`eval 'as_val=${'$as_ac_var'}
+          $as_echo "$as_val"'`
+            { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+ $as_echo "$ac_res" >&6; }
+ as_val=`eval 'as_val=${'$as_ac_var'}
+          $as_echo "$as_val"'`
+    if test "x$as_val" = x""yes; then
+   cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+ _ACEOF
+
+ fi
+ done
+
+   # OpenSSL versions before 1.1.0 required setting callback functions, for
+   # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
+   # function was removed.
+
+ for ac_func in CRYPTO_lock
+ do
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
+ $as_echo_n "checking for $ac_func... " >&6; }
+ if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+   $as_echo_n "(cached) " >&6
+ else
+   cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h.  */
+ _ACEOF
+ cat confdefs.h >>conftest.$ac_ext
+ cat >>conftest.$ac_ext <<_ACEOF
+ /* end confdefs.h.  */
+ /* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+    For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+ #define $ac_func innocuous_$ac_func
+
+ /* System header to define __stub macros and hopefully few prototypes,
+     which can conflict with char $ac_func (); below.
+     Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+     <limits.h> exists even on freestanding compilers.  */
+
+ #ifdef __STDC__
+ # include <limits.h>
+ #else
+ # include <assert.h>
+ #endif
+
+ #undef $ac_func
+
+ /* Override any GCC internal prototype to avoid an error.
+    Use char because int might match the return type of a GCC
+    builtin and then its argument prototype would still apply.  */
+ #ifdef __cplusplus
+ extern "C"
+ #endif
+ char $ac_func ();
+ /* The GNU C library defines this for functions which it implements
+     to always fail with ENOSYS.  Some functions are actually named
+     something starting with __ and the normal name is an alias.  */
+ #if defined __stub_$ac_func || defined __stub___$ac_func
+ choke me
+ #endif
+
+ int
+ main ()
+ {
+ return $ac_func ();
+   ;
+   return 0;
+ }
+ _ACEOF
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { (ac_try="$ac_link"
+ case "(($ac_try" in
+   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+   *) ac_try_echo=$ac_try;;
+ esac
+ eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+ $as_echo "$ac_try_echo") >&5
+   (eval "$ac_link") 2>conftest.er1
+   ac_status=$?
+   grep -v '^ *+' conftest.er1 >conftest.err
+   rm -f conftest.er1
+   cat conftest.err >&5
+   $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } && {
+      test -z "$ac_c_werror_flag" ||
+      test ! -s conftest.err
+        } && test -s conftest$ac_exeext && {
+      test "$cross_compiling" = yes ||
+      $as_test_x conftest$ac_exeext
+        }; then
+   eval "$as_ac_var=yes"
+ else
+   $as_echo "$as_me: failed program was:" >&5
+ sed 's/^/| /' conftest.$ac_ext >&5
+
+     eval "$as_ac_var=no"
+ fi
+
+ rm -rf conftest.dSYM
+ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+       conftest$ac_exeext conftest.$ac_ext
+ fi
+ ac_res=`eval 'as_val=${'$as_ac_var'}
+          $as_echo "$as_val"'`
+            { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+ $as_echo "$ac_res" >&6; }
+ as_val=`eval 'as_val=${'$as_ac_var'}
+          $as_echo "$as_val"'`
+    if test "x$as_val" = x""yes; then
+   cat >>confdefs.h <<_ACEOF
+ #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+ _ACEOF
+
+ fi
+ done
+
  fi

  if test "$with_pam" = yes ; then
diff --git a/configure.in b/configure.in
index e00adc9..aad7598 100644
*** a/configure.in
--- b/configure.in
*************** if test "$with_openssl" = yes ; then
*** 951,961 ****
    dnl Order matters!
    if test "$PORTNAME" != "win32"; then
       AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, [], [AC_MSG_ERROR([library 'crypto' is required for OpenSSL])])
!      AC_CHECK_LIB(ssl,    SSL_library_init, [], [AC_MSG_ERROR([library 'ssl' is required for OpenSSL])])
    else
       AC_SEARCH_LIBS(CRYPTO_new_ex_data, eay32 crypto, [], [AC_MSG_ERROR([library 'eay32' or 'crypto' is required for
OpenSSL])])
!      AC_SEARCH_LIBS(SSL_library_init, ssleay32 ssl, [], [AC_MSG_ERROR([library 'ssleay32' or 'ssl' is required for
OpenSSL])])
    fi
  fi

  if test "$with_pam" = yes ; then
--- 951,971 ----
    dnl Order matters!
    if test "$PORTNAME" != "win32"; then
       AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, [], [AC_MSG_ERROR([library 'crypto' is required for OpenSSL])])
!      AC_CHECK_LIB(ssl,    SSL_new, [], [AC_MSG_ERROR([library 'ssl' is required for OpenSSL])])
    else
       AC_SEARCH_LIBS(CRYPTO_new_ex_data, eay32 crypto, [], [AC_MSG_ERROR([library 'eay32' or 'crypto' is required for
OpenSSL])])
!      AC_SEARCH_LIBS(SSL_new, ssleay32 ssl, [], [AC_MSG_ERROR([library 'ssleay32' or 'ssl' is required for OpenSSL])])
    fi
+   # Functions introduced in OpenSSL 1.1.0. We used to check for
+   # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
+   # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
+   # doesn't have these OpenSSL 1.1.0 functions. So check for individual
+   # functions.
+   AC_CHECK_FUNCS([OPENSSL_init_ssl BIO_meth_new ASN1_STRING_get0_data RAND_OpenSSL])
+   # OpenSSL versions before 1.1.0 required setting callback functions, for
+   # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
+   # function was removed.
+   AC_CHECK_FUNCS([CRYPTO_lock])
  fi

  if test "$with_pam" = yes ; then
diff --git a/contrib/pgcrypto/internal.c b/contrib/pgcrypto/internal.c
index cb8ba26..02ff976 100644
*** a/contrib/pgcrypto/internal.c
--- b/contrib/pgcrypto/internal.c
*************** px_find_cipher(const char *name, PX_Ciph
*** 620,634 ****
   * Randomness provider
   */

- /*
-  * Use always strong randomness.
-  */
- int
- px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
- {
-     return px_get_random_bytes(dst, count);
- }
-
  static time_t seed_time = 0;
  static time_t check_time = 0;

--- 620,625 ----
diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c
index e49dbaf..9ae45b2 100644
*** a/contrib/pgcrypto/openssl.c
--- b/contrib/pgcrypto/openssl.c
***************
*** 40,45 ****
--- 40,48 ----
  #include <openssl/rand.h>
  #include <openssl/err.h>

+ #include "utils/memutils.h"
+ #include "utils/resowner.h"
+
  /*
   * Max lengths we might want to handle.
   */
*************** compat_find_digest(const char *name, PX_
*** 199,216 ****
   * Hashes
   */

  typedef struct OSSLDigest
  {
      const EVP_MD *algo;
!     EVP_MD_CTX    ctx;
  } OSSLDigest;

  static unsigned
  digest_result_size(PX_MD *h)
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     return EVP_MD_CTX_size(&digest->ctx);
  }

  static unsigned
--- 202,274 ----
   * Hashes
   */

+ /*
+  * To make sure we don't leak OpenSSL handles on abort, we keep OSSLDigest
+  * objects in a linked list, allocated in TopMemoryContext. We use the
+  * ResourceOwner mechanism to free them on abort.
+  */
  typedef struct OSSLDigest
  {
      const EVP_MD *algo;
!     EVP_MD_CTX *ctx;
!
!     ResourceOwner owner;
!     struct OSSLDigest *next;
!     struct OSSLDigest *prev;
  } OSSLDigest;

+ static OSSLDigest *open_digests = NULL;
+ static bool resowner_callback_registered = false;
+
+ static void
+ free_openssldigest(OSSLDigest *digest)
+ {
+     EVP_MD_CTX_destroy(digest->ctx);
+     if (digest->prev)
+         digest->prev->next = digest->next;
+     else
+         open_digests = digest->next;
+     if (digest->next)
+         digest->next->prev = digest->prev;
+     pfree(digest);
+ }
+
+ /*
+  * Close any open OpenSSL handles on abort.
+  */
+ static void
+ digest_free_callback(ResourceReleasePhase phase,
+                      bool isCommit,
+                      bool isTopLevel,
+                      void *arg)
+ {
+     OSSLDigest *curr;
+     OSSLDigest *next;
+
+     if (phase != RESOURCE_RELEASE_AFTER_LOCKS)
+         return;
+
+     next = open_digests;
+     while (next)
+     {
+         curr = next;
+         next = curr->next;
+
+         if (curr->owner == CurrentResourceOwner)
+         {
+             if (isCommit)
+                 elog(WARNING, "pgcrypto digest reference leak: digest %p still referenced", curr);
+             free_openssldigest(curr);
+         }
+     }
+ }
+
  static unsigned
  digest_result_size(PX_MD *h)
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     return EVP_MD_CTX_size(digest->ctx);
  }

  static unsigned
*************** digest_block_size(PX_MD *h)
*** 218,224 ****
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     return EVP_MD_CTX_block_size(&digest->ctx);
  }

  static void
--- 276,282 ----
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     return EVP_MD_CTX_block_size(digest->ctx);
  }

  static void
*************** digest_reset(PX_MD *h)
*** 226,232 ****
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL);
  }

  static void
--- 284,290 ----
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     EVP_DigestInit_ex(digest->ctx, digest->algo, NULL);
  }

  static void
*************** digest_update(PX_MD *h, const uint8 *dat
*** 234,240 ****
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     EVP_DigestUpdate(&digest->ctx, data, dlen);
  }

  static void
--- 292,298 ----
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     EVP_DigestUpdate(digest->ctx, data, dlen);
  }

  static void
*************** digest_finish(PX_MD *h, uint8 *dst)
*** 242,248 ****
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     EVP_DigestFinal_ex(&digest->ctx, dst, NULL);
  }

  static void
--- 300,306 ----
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     EVP_DigestFinal_ex(digest->ctx, dst, NULL);
  }

  static void
*************** digest_free(PX_MD *h)
*** 250,258 ****
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     EVP_MD_CTX_cleanup(&digest->ctx);
!
!     px_free(digest);
      px_free(h);
  }

--- 308,314 ----
  {
      OSSLDigest *digest = (OSSLDigest *) h->p.ptr;

!     free_openssldigest(digest);
      px_free(h);
  }

*************** int
*** 264,269 ****
--- 320,326 ----
  px_find_digest(const char *name, PX_MD **res)
  {
      const EVP_MD *md;
+     EVP_MD_CTX *ctx;
      PX_MD       *h;
      OSSLDigest *digest;

*************** px_find_digest(const char *name, PX_MD *
*** 273,289 ****
          OpenSSL_add_all_algorithms();
      }

      md = EVP_get_digestbyname(name);
      if (md == NULL)
          return compat_find_digest(name, res);

!     digest = px_alloc(sizeof(*digest));
!     digest->algo = md;

!     EVP_MD_CTX_init(&digest->ctx);
!     if (EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL) == 0)
          return -1;

      h = px_alloc(sizeof(*h));
      h->result_size = digest_result_size;
      h->block_size = digest_block_size;
--- 330,372 ----
          OpenSSL_add_all_algorithms();
      }

+     if (!resowner_callback_registered)
+     {
+         RegisterResourceReleaseCallback(digest_free_callback, NULL);
+         resowner_callback_registered = true;
+     }
+
      md = EVP_get_digestbyname(name);
      if (md == NULL)
          return compat_find_digest(name, res);

!     /*
!      * Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object.
!      * The order is crucial, to make sure we don't leak anything on
!      * out-of-memory or other error.
!      */
!     digest = MemoryContextAlloc(TopMemoryContext, sizeof(*digest));

!     ctx = EVP_MD_CTX_create();
!     if (!ctx)
!     {
!         pfree(digest);
          return -1;
+     }
+     if (EVP_DigestInit_ex(ctx, md, NULL) == 0)
+     {
+         pfree(digest);
+         return -1;
+     }
+
+     digest->algo = md;
+     digest->ctx = ctx;
+     digest->owner = CurrentResourceOwner;
+     digest->next = open_digests;
+     digest->prev = NULL;
+     open_digests = digest;

+     /* The PX_MD object is allocated in the current memory context. */
      h = px_alloc(sizeof(*h));
      h->result_size = digest_result_size;
      h->block_size = digest_block_size;
*************** static void
*** 987,993 ****
--- 1070,1082 ----
  init_openssl_rand(void)
  {
      if (RAND_get_rand_method() == NULL)
+     {
+ #ifdef HAVE_RAND_OPENSSL
+         RAND_set_rand_method(RAND_OpenSSL());
+ #else
          RAND_set_rand_method(RAND_SSLeay());
+ #endif
+     }
      openssl_random_init = 1;
  }

*************** px_get_random_bytes(uint8 *dst, unsigned
*** 1007,1027 ****
  }

  int
- px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
- {
-     int            res;
-
-     if (!openssl_random_init)
-         init_openssl_rand();
-
-     res = RAND_pseudo_bytes(dst, count);
-     if (res == 0 || res == 1)
-         return count;
-
-     return PXE_OSSL_RAND_ERROR;
- }
-
- int
  px_add_entropy(const uint8 *data, unsigned count)
  {
      /*
--- 1096,1101 ----
diff --git a/contrib/pgcrypto/pgp-s2k.c b/contrib/pgcrypto/pgp-s2k.c
index 5f47e79..fb651fc 100644
*** a/contrib/pgcrypto/pgp-s2k.c
--- b/contrib/pgcrypto/pgp-s2k.c
*************** pgp_s2k_fill(PGP_S2K *s2k, int mode, int
*** 223,235 ****
          case 0:
              break;
          case 1:
!             res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT);
              break;
          case 3:
!             res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT);
              if (res < 0)
                  break;
!             res = px_get_pseudo_random_bytes(&tmp, 1);
              if (res < 0)
                  break;
              s2k->iter = decide_count(tmp);
--- 223,235 ----
          case 0:
              break;
          case 1:
!             res = px_get_random_bytes(s2k->salt, PGP_S2K_SALT);
              break;
          case 3:
!             res = px_get_random_bytes(s2k->salt, PGP_S2K_SALT);
              if (res < 0)
                  break;
!             res = px_get_random_bytes(&tmp, 1);
              if (res < 0)
                  break;
              s2k->iter = decide_count(tmp);
diff --git a/contrib/pgcrypto/px-crypt.c b/contrib/pgcrypto/px-crypt.c
index e3246fc..3d42393 100644
*** a/contrib/pgcrypto/px-crypt.c
--- b/contrib/pgcrypto/px-crypt.c
*************** px_gen_salt(const char *salt_type, char
*** 153,159 ****
              return PXE_BAD_SALT_ROUNDS;
      }

!     res = px_get_pseudo_random_bytes((uint8 *) rbuf, g->input_len);
      if (res < 0)
          return res;

--- 153,159 ----
              return PXE_BAD_SALT_ROUNDS;
      }

!     res = px_get_random_bytes((uint8 *) rbuf, g->input_len);
      if (res < 0)
          return res;

diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h
index d237d97..fa889eb 100644
*** a/contrib/pgcrypto/px.h
--- b/contrib/pgcrypto/px.h
*************** int            px_find_cipher(const char *name, P
*** 190,196 ****
  int            px_find_combo(const char *name, PX_Combo **res);

  int            px_get_random_bytes(uint8 *dst, unsigned count);
- int            px_get_pseudo_random_bytes(uint8 *dst, unsigned count);
  int            px_add_entropy(const uint8 *data, unsigned count);

  unsigned    px_acquire_system_randomness(uint8 *dst);
--- 190,195 ----
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 82a608d..0122b0d 100644
*** a/src/backend/libpq/be-secure.c
--- b/src/backend/libpq/be-secure.c
***************
*** 66,72 ****
  #ifdef USE_SSL
  #include <openssl/ssl.h>
  #include <openssl/dh.h>
! #if SSLEAY_VERSION_NUMBER >= 0x0907000L
  #include <openssl/conf.h>
  #endif
  #endif   /* USE_SSL */
--- 66,72 ----
  #ifdef USE_SSL
  #include <openssl/ssl.h>
  #include <openssl/dh.h>
! #if OPENSSL_VERSION_NUMBER >= 0x0907000L
  #include <openssl/conf.h>
  #endif
  #endif   /* USE_SSL */
***************
*** 80,85 ****
--- 80,86 ----

  static DH  *load_dh_file(int keylength);
  static DH  *load_dh_buffer(const char *, size_t);
+ static DH  *generate_dh_parameters(int prime_len, int generator);
  static DH  *tmp_dh_cb(SSL *s, int is_export, int keylength);
  static int    verify_cb(int, X509_STORE_CTX *);
  static void info_cb(const SSL *ssl, int type, int args);
*************** wloop:
*** 423,430 ****
   * to retry; do we need to adopt their logic for that?
   */

! static bool my_bio_initialized = false;
! static BIO_METHOD my_bio_methods;

  static int
  my_sock_read(BIO *h, char *buf, int size)
--- 424,430 ----
   * to retry; do we need to adopt their logic for that?
   */

! static BIO_METHOD *my_bio_methods = NULL;

  static int
  my_sock_read(BIO *h, char *buf, int size)
*************** my_sock_read(BIO *h, char *buf, int size
*** 435,441 ****

      if (buf != NULL)
      {
!         res = recv(h->num, buf, size, 0);
          BIO_clear_retry_flags(h);
          if (res <= 0)
          {
--- 435,441 ----

      if (buf != NULL)
      {
!         res = recv(BIO_get_fd(h, NULL), buf, size, 0);
          BIO_clear_retry_flags(h);
          if (res <= 0)
          {
*************** my_sock_write(BIO *h, const char *buf, i
*** 457,463 ****
  {
      int            res = 0;

!     res = send(h->num, buf, size, 0);
      BIO_clear_retry_flags(h);
      if (res <= 0)
      {
--- 457,463 ----
  {
      int            res = 0;

!     res = send(BIO_get_fd(h, NULL), buf, size, 0);
      BIO_clear_retry_flags(h);
      if (res <= 0)
      {
*************** my_sock_write(BIO *h, const char *buf, i
*** 473,486 ****
  static BIO_METHOD *
  my_BIO_s_socket(void)
  {
!     if (!my_bio_initialized)
      {
!         memcpy(&my_bio_methods, BIO_s_socket(), sizeof(BIO_METHOD));
!         my_bio_methods.bread = my_sock_read;
!         my_bio_methods.bwrite = my_sock_write;
!         my_bio_initialized = true;
      }
!     return &my_bio_methods;
  }

  /* This should exactly match openssl's SSL_set_fd except for using my BIO */
--- 473,513 ----
  static BIO_METHOD *
  my_BIO_s_socket(void)
  {
!     if (!my_bio_methods)
      {
!         BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket();
! #ifdef HAVE_BIO_METH_NEW
!         int            my_bio_index;
!
!         my_bio_index = BIO_get_new_index();
!         if (my_bio_index == -1)
!             return NULL;
!         my_bio_methods = BIO_meth_new(my_bio_index, "PostgreSQL backend socket");
!         if (!my_bio_methods)
!             return NULL;
!         if (!BIO_meth_set_write(my_bio_methods, my_sock_write) ||
!             !BIO_meth_set_read(my_bio_methods, my_sock_read) ||
!             !BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) ||
!             !BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) ||
!             !BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) ||
!             !BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) ||
!             !BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) ||
!             !BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom)))
!         {
!             BIO_meth_free(my_bio_methods);
!             my_bio_methods = NULL;
!             return NULL;
!         }
! #else
!         my_bio_methods = malloc(sizeof(BIO_METHOD));
!         if (!my_bio_methods)
!             return NULL;
!         memcpy(my_bio_methods, biom, sizeof(BIO_METHOD));
!         my_bio_methods->bread = my_sock_read;
!         my_bio_methods->bwrite = my_sock_write;
! #endif
      }
!     return my_bio_methods;
  }

  /* This should exactly match openssl's SSL_set_fd except for using my BIO */
*************** static int
*** 488,496 ****
  my_SSL_set_fd(SSL *s, int fd)
  {
      int            ret = 0;
!     BIO           *bio = NULL;

!     bio = BIO_new(my_BIO_s_socket());

      if (bio == NULL)
      {
--- 515,530 ----
  my_SSL_set_fd(SSL *s, int fd)
  {
      int            ret = 0;
!     BIO           *bio;
!     BIO_METHOD *bio_method;

!     bio_method = my_BIO_s_socket();
!     if (bio_method == NULL)
!     {
!         SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
!         goto err;
!     }
!     bio = BIO_new(bio_method);

      if (bio == NULL)
      {
*************** load_dh_buffer(const char *buffer, size_
*** 590,595 ****
--- 624,654 ----
  }

  /*
+  *    Generate DH parameters.
+  *
+  *    Last resort if we can't load precomputed nor hardcoded
+  *    parameters.
+  */
+ static DH  *
+ generate_dh_parameters(int prime_len, int generator)
+ {
+ #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
+     DH           *dh;
+
+     if ((dh = DH_new()) == NULL)
+         return NULL;
+
+     if (DH_generate_parameters_ex(dh, prime_len, generator, NULL))
+         return dh;
+
+     DH_free(dh);
+     return NULL;
+ #else
+     return DH_generate_parameters(prime_len, generator, NULL, NULL);
+ #endif
+ }
+
+ /*
   *    Generate an ephemeral DH key.  Because this can take a long
   *    time to compute, we can use precomputed parameters of the
   *    common key sizes.
*************** tmp_dh_cb(SSL *s, int is_export, int key
*** 658,664 ****
          ereport(DEBUG2,
                  (errmsg_internal("DH: generating parameters (%d bits)",
                                   keylength)));
!         r = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL);
      }

      return r;
--- 717,723 ----
          ereport(DEBUG2,
                  (errmsg_internal("DH: generating parameters (%d bits)",
                                   keylength)));
!         r = generate_dh_parameters(keylength, DH_GENERATOR_2);
      }

      return r;
*************** initialize_SSL(void)
*** 737,747 ****
--- 796,810 ----

      if (!SSL_context)
      {
+ #ifdef HAVE_OPENSSL_INIT_SSL
+         OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
+ #else
  #if SSLEAY_VERSION_NUMBER >= 0x0907000L
          OPENSSL_config(NULL);
  #endif
          SSL_library_init();
          SSL_load_error_strings();
+ #endif

          /*
           * We use SSLv23_method() because it can negotiate use of the highest
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 985e5a7..872d39f 100644
*** a/src/include/pg_config.h.in
--- b/src/include/pg_config.h.in
***************
*** 87,92 ****
--- 87,98 ----
  /* Define to 1 if you have the `append_history' function. */
  #undef HAVE_APPEND_HISTORY

+ /* Define to 1 if you have the `ASN1_STRING_get0_data' function. */
+ #undef HAVE_ASN1_STRING_GET0_DATA
+
+ /* Define to 1 if you have the `BIO_meth_new' function. */
+ #undef HAVE_BIO_METH_NEW
+
  /* Define to 1 if you have the `cbrt' function. */
  #undef HAVE_CBRT

***************
*** 99,104 ****
--- 105,113 ----
  /* Define to 1 if you have the `crypt' function. */
  #undef HAVE_CRYPT

+ /* Define to 1 if you have the `CRYPTO_lock' function. */
+ #undef HAVE_CRYPTO_LOCK
+
  /* Define to 1 if you have the <crypt.h> header file. */
  #undef HAVE_CRYPT_H

***************
*** 357,362 ****
--- 366,374 ----
  /* Define to 1 if you have the <net/if.h> header file. */
  #undef HAVE_NET_IF_H

+ /* Define to 1 if you have the `OPENSSL_init_ssl' function. */
+ #undef HAVE_OPENSSL_INIT_SSL
+
  /* Define to 1 if you have the <ossp/uuid.h> header file. */
  #undef HAVE_OSSP_UUID_H

***************
*** 396,401 ****
--- 408,416 ----
  /* Define to 1 if you have the `random' function. */
  #undef HAVE_RANDOM

+ /* Define to 1 if you have the `RAND_OpenSSL' function. */
+ #undef HAVE_RAND_OPENSSL
+
  /* Define to 1 if you have the <readline.h> header file. */
  #undef HAVE_READLINE_H

diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index 9e7ae47..a52a206 100644
*** a/src/interfaces/libpq/fe-secure.c
--- b/src/interfaces/libpq/fe-secure.c
***************
*** 58,64 ****
  #ifdef USE_SSL

  #include <openssl/ssl.h>
! #if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
  #include <openssl/conf.h>
  #endif
  #ifdef USE_SSL_ENGINE
--- 58,64 ----
  #ifdef USE_SSL

  #include <openssl/ssl.h>
! #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
  #include <openssl/conf.h>
  #endif
  #ifdef USE_SSL_ENGINE
*************** verify_peer_name_matches_certificate(PGc
*** 835,843 ****
      return result;
  }

! #ifdef ENABLE_THREAD_SAFETY
  /*
!  *    Callback functions for OpenSSL internal locking
   */

  static unsigned long
--- 835,847 ----
      return result;
  }

! #if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK)
  /*
!  *    Callback functions for OpenSSL internal locking.  (OpenSSL 1.1.0
!  *    does its own locking, and doesn't need these anymore.  The
!  *    CRYPTO_lock() function was removed in 1.1.0, when the callbacks
!  *    were made obsolete, so we assume that if CRYPTO_lock() exists,
!  *    the callbacks are still required.)
   */

  static unsigned long
*************** pq_lockingcallback(int mode, int n, cons
*** 867,873 ****
              PGTHREAD_ERROR("failed to unlock mutex");
      }
  }
! #endif   /* ENABLE_THREAD_SAFETY */

  /*
   * Initialize SSL library.
--- 871,877 ----
              PGTHREAD_ERROR("failed to unlock mutex");
      }
  }
! #endif   /* ENABLE_THREAD_SAFETY && HAVE_CRYPTO_LOCK */

  /*
   * Initialize SSL library.
*************** init_ssl_system(PGconn *conn)
*** 905,910 ****
--- 909,915 ----
      if (pthread_mutex_lock(&ssl_config_mutex))
          return -1;

+ #ifdef HAVE_CRYPTO_LOCK
      if (pq_init_crypto_lib)
      {
          /*
*************** init_ssl_system(PGconn *conn)
*** 940,956 ****
              CRYPTO_set_locking_callback(pq_lockingcallback);
          }
      }
  #endif   /* ENABLE_THREAD_SAFETY */

      if (!ssl_lib_initialized)
      {
          if (pq_init_ssl_lib)
          {
! #if SSLEAY_VERSION_NUMBER >= 0x00907000L
              OPENSSL_config(NULL);
  #endif
              SSL_library_init();
              SSL_load_error_strings();
          }
          ssl_lib_initialized = true;
      }
--- 945,966 ----
              CRYPTO_set_locking_callback(pq_lockingcallback);
          }
      }
+ #endif   /* HAVE_CRYPTO_LOCK */
  #endif   /* ENABLE_THREAD_SAFETY */

      if (!ssl_lib_initialized)
      {
          if (pq_init_ssl_lib)
          {
! #ifdef HAVE_OPENSSL_INIT_SSL
!             OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
! #else
! #if OPENSSL_VERSION_NUMBER >= 0x00907000L
              OPENSSL_config(NULL);
  #endif
              SSL_library_init();
              SSL_load_error_strings();
+ #endif
          }
          ssl_lib_initialized = true;
      }
*************** init_ssl_system(PGconn *conn)
*** 970,981 ****
   *    if we had any.)
   *
   *    Callbacks are only set when we're compiled in threadsafe mode, so
!  *    we only need to remove them in this case.
   */
  static void
  destroy_ssl_system(void)
  {
! #ifdef ENABLE_THREAD_SAFETY
      /* Mutex is created in initialize_ssl_system() */
      if (pthread_mutex_lock(&ssl_config_mutex))
          return;
--- 980,992 ----
   *    if we had any.)
   *
   *    Callbacks are only set when we're compiled in threadsafe mode, so
!  *    we only need to remove them in this case. They are also not needed
!  *    with OpenSSL 1.1.0 anymore.
   */
  static void
  destroy_ssl_system(void)
  {
! #if defined(ENABLE_THREAD_SAFETY) && defined(HAVE_CRYPTO_LOCK)
      /* Mutex is created in initialize_ssl_system() */
      if (pthread_mutex_lock(&ssl_config_mutex))
          return;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index f14cf2b..ba1bfac 100644
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
*************** typedef struct
*** 77,83 ****
  #include <openssl/ssl.h>
  #include <openssl/err.h>

! #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
  #define USE_SSL_ENGINE
  #endif
  #endif   /* USE_SSL */
--- 77,83 ----
  #include <openssl/ssl.h>
  #include <openssl/err.h>

! #if (OPENSSL_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
  #define USE_SSL_ENGINE
  #endif
  #endif   /* USE_SSL */

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: [HACKERS] OpenSSL support in our back branches
Next
From: Tom Lane
Date:
Subject: Re: [HACKERS] OpenSSL 1.1 breaks configure and more