0001-Fix-compilation-with-OpenSSL-1.1.patch
application/x-patch
Filename: 0001-Fix-compilation-with-OpenSSL-1.1.patch
Type: application/x-patch
Part: 0
Patch
Format: format-patch
Series: patch 0001
Subject: Fix compilation with OpenSSL 1.1.
| File | + | − |
|---|---|---|
| configure | 22 | 22 |
| configure.in | 2 | 2 |
| contrib/pgcrypto/openssl.c | 101 | 14 |
| contrib/sslinfo/sslinfo.c | 2 | 12 |
| src/backend/libpq/be-secure-openssl.c | 27 | 12 |
| src/interfaces/libpq/fe-secure-openssl.c | 27 | 12 |
From 4534d01a0471d7378100cddebb5641800950e6c6 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Mon, 5 Sep 2016 13:46:15 +0300
Subject: [PATCH 1/2] Fix compilation with OpenSSL 1.1.
- Check for SSL_new in configure, now that SSL_library_init is a macro.
- Do not access struct members directly. This includes some new code in
pgcrypto, to use the resource owner mechanism to ensure that we don't
leak OpenSSL handles, now that we don't palloc them as part of other
structs anymore.
- RAND_SSLeay was renamed to RAND_OpenSSL
Andreas Karlsson, with some changes by me.
---
configure | 44 ++++++------
configure.in | 4 +-
contrib/pgcrypto/openssl.c | 115 +++++++++++++++++++++++++++----
contrib/sslinfo/sslinfo.c | 14 +---
src/backend/libpq/be-secure-openssl.c | 39 +++++++----
src/interfaces/libpq/fe-secure-openssl.c | 39 +++++++----
6 files changed, 181 insertions(+), 74 deletions(-)
diff --git a/configure b/configure
index 45c8eef..caf6f26 100755
--- a/configure
+++ b/configure
@@ -9538,9 +9538,9 @@ else
as_fn_error $? "library 'crypto' is required for OpenSSL" "$LINENO" 5
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_library_init in -lssl" >&5
-$as_echo_n "checking for SSL_library_init in -lssl... " >&6; }
-if ${ac_cv_lib_ssl_SSL_library_init+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl" >&5
+$as_echo_n "checking for SSL_new in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_SSL_new+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
@@ -9554,27 +9554,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
-char SSL_library_init ();
+char SSL_new ();
int
main ()
{
-return SSL_library_init ();
+return SSL_new ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_ssl_SSL_library_init=yes
+ ac_cv_lib_ssl_SSL_new=yes
else
- ac_cv_lib_ssl_SSL_library_init=no
+ ac_cv_lib_ssl_SSL_new=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$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" = xyes; then :
+{ $as_echo "$as_me:${as_lineno-$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" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBSSL 1
_ACEOF
@@ -9644,9 +9644,9 @@ else
as_fn_error $? "library 'eay32' or 'crypto' is required for OpenSSL" "$LINENO" 5
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing SSL_library_init" >&5
-$as_echo_n "checking for library containing SSL_library_init... " >&6; }
-if ${ac_cv_search_SSL_library_init+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing SSL_new" >&5
+$as_echo_n "checking for library containing SSL_new... " >&6; }
+if ${ac_cv_search_SSL_new+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
@@ -9659,11 +9659,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
#ifdef __cplusplus
extern "C"
#endif
-char SSL_library_init ();
+char SSL_new ();
int
main ()
{
-return SSL_library_init ();
+return SSL_new ();
;
return 0;
}
@@ -9676,25 +9676,25 @@ for ac_lib in '' ssleay32 ssl; do
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_SSL_library_init=$ac_res
+ ac_cv_search_SSL_new=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if ${ac_cv_search_SSL_library_init+:} false; then :
+ if ${ac_cv_search_SSL_new+:} false; then :
break
fi
done
-if ${ac_cv_search_SSL_library_init+:} false; then :
+if ${ac_cv_search_SSL_new+:} false; then :
else
- ac_cv_search_SSL_library_init=no
+ ac_cv_search_SSL_new=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$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
+{ $as_echo "$as_me:${as_lineno-$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"
diff --git a/configure.in b/configure.in
index c878b4e..c426806 100644
--- a/configure.in
+++ b/configure.in
@@ -1112,10 +1112,10 @@ if test "$with_openssl" = yes ; then
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])])
+ 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_library_init, ssleay32 ssl, [], [AC_MSG_ERROR([library 'ssleay32' or 'ssl' is required for OpenSSL])])
+ AC_SEARCH_LIBS(SSL_new, ssleay32 ssl, [], [AC_MSG_ERROR([library 'ssleay32' or 'ssl' is required for OpenSSL])])
fi
AC_CHECK_FUNCS([SSL_get_current_compression])
fi
diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c
index ffab5d2..0247ebb 100644
--- a/contrib/pgcrypto/openssl.c
+++ b/contrib/pgcrypto/openssl.c
@@ -41,6 +41,9 @@
#include <openssl/rand.h>
#include <openssl/err.h>
+#include "utils/memutils.h"
+#include "utils/resowner.h"
+
/*
* Max lengths we might want to handle.
*/
@@ -51,18 +54,73 @@
* 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;
+ 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);
+ return EVP_MD_CTX_size(digest->ctx);
}
static unsigned
@@ -70,7 +128,7 @@ digest_block_size(PX_MD *h)
{
OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
- return EVP_MD_CTX_block_size(&digest->ctx);
+ return EVP_MD_CTX_block_size(digest->ctx);
}
static void
@@ -78,7 +136,7 @@ digest_reset(PX_MD *h)
{
OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
- EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL);
+ EVP_DigestInit_ex(digest->ctx, digest->algo, NULL);
}
static void
@@ -86,7 +144,7 @@ digest_update(PX_MD *h, const uint8 *data, unsigned dlen)
{
OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
- EVP_DigestUpdate(&digest->ctx, data, dlen);
+ EVP_DigestUpdate(digest->ctx, data, dlen);
}
static void
@@ -94,7 +152,7 @@ digest_finish(PX_MD *h, uint8 *dst)
{
OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
- EVP_DigestFinal_ex(&digest->ctx, dst, NULL);
+ EVP_DigestFinal_ex(digest->ctx, dst, NULL);
}
static void
@@ -102,9 +160,7 @@ digest_free(PX_MD *h)
{
OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
- EVP_MD_CTX_cleanup(&digest->ctx);
-
- px_free(digest);
+ free_openssldigest(digest);
px_free(h);
}
@@ -116,6 +172,7 @@ int
px_find_digest(const char *name, PX_MD **res)
{
const EVP_MD *md;
+ EVP_MD_CTX *ctx;
PX_MD *h;
OSSLDigest *digest;
@@ -125,17 +182,43 @@ px_find_digest(const char *name, PX_MD **res)
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 PXE_NO_HASH;
- digest = px_alloc(sizeof(*digest));
- digest->algo = md;
+ /*
+ * 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));
- EVP_MD_CTX_init(&digest->ctx);
- if (EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL) == 0)
+ 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;
@@ -831,6 +914,10 @@ px_find_cipher(const char *name, PX_Cipher **res)
static int openssl_random_init = 0;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#define RAND_OpenSSL RAND_SSLeay
+#endif
+
/*
* OpenSSL random should re-feeded occasionally. From /dev/urandom
* preferably.
@@ -839,7 +926,7 @@ static void
init_openssl_rand(void)
{
if (RAND_get_rand_method() == NULL)
- RAND_set_rand_method(RAND_SSLeay());
+ RAND_set_rand_method(RAND_OpenSSL());
openssl_random_init = 1;
}
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 82a4c1b..a4b0f9b 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -402,8 +402,6 @@ ssl_extension_info(PG_FUNCTION_ARGS)
MemoryContext oldcontext;
SSLExtensionInfoContext *fctx;
- STACK_OF(X509_EXTENSION) *ext_stack = NULL;
-
if (SRF_IS_FIRSTCALL())
{
@@ -427,16 +425,10 @@ ssl_extension_info(PG_FUNCTION_ARGS)
errmsg("function returning record called in context that cannot accept type record")));
fctx->tupdesc = BlessTupleDesc(tupdesc);
- /* Get all extensions of certificate */
- if (cert && cert->cert_info)
- ext_stack = cert->cert_info->extensions;
-
/* Set max_calls as a count of extensions in certificate */
max_calls = cert != NULL ? X509_get_ext_count(cert) : 0;
- if (cert != NULL &&
- ext_stack != NULL &&
- max_calls > 0)
+ if (max_calls > 0)
{
/* got results, keep track of them */
funcctx->max_calls = max_calls;
@@ -462,8 +454,6 @@ ssl_extension_info(PG_FUNCTION_ARGS)
max_calls = funcctx->max_calls;
fctx = funcctx->user_fctx;
- ext_stack = cert->cert_info->extensions;
-
/* do while there are more left to send */
if (call_cntr < max_calls)
{
@@ -486,7 +476,7 @@ ssl_extension_info(PG_FUNCTION_ARGS)
errmsg("could not create OpenSSL BIO structure")));
/* Get the extension from the certificate */
- ext = sk_X509_EXTENSION_value(ext_stack, call_cntr);
+ ext = X509_get_ext(cert, call_cntr);
obj = X509_EXTENSION_get_object(ext);
/* Get the extension name */
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index bb0d2d9..f4aaf40 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -667,8 +667,12 @@ be_tls_write(Port *port, void *ptr, size_t len, int *waitfor)
* to retry; do we need to adopt their logic for that?
*/
-static bool my_bio_initialized = false;
-static BIO_METHOD my_bio_methods;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#define BIO_get_data(bio) (bio->ptr)
+#define BIO_set_data(bio, data) (bio->ptr = data)
+#endif
+
+static BIO_METHOD *my_bio_methods = NULL;
static int
my_sock_read(BIO *h, char *buf, int size)
@@ -677,7 +681,7 @@ my_sock_read(BIO *h, char *buf, int size)
if (buf != NULL)
{
- res = secure_raw_read(((Port *) h->ptr), buf, size);
+ res = secure_raw_read(((Port *) BIO_get_data(h)), buf, size);
BIO_clear_retry_flags(h);
if (res <= 0)
{
@@ -697,7 +701,7 @@ my_sock_write(BIO *h, const char *buf, int size)
{
int res = 0;
- res = secure_raw_write(((Port *) h->ptr), buf, size);
+ res = secure_raw_write(((Port *) BIO_get_data(h)), buf, size);
BIO_clear_retry_flags(h);
if (res <= 0)
{
@@ -714,14 +718,26 @@ my_sock_write(BIO *h, const char *buf, int size)
static BIO_METHOD *
my_BIO_s_socket(void)
{
- if (!my_bio_initialized)
+ if (!my_bio_methods)
{
- 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;
+ BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket();
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ my_bio_methods = BIO_meth_new(BIO_TYPE_SOCKET, "pgsocket");
+ 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_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));
+#else
+ my_bio_methods = malloc(sizeof(BIO_METHOD));
+ 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;
+ return my_bio_methods;
}
/* This should exactly match openssl's SSL_set_fd except for using my BIO */
@@ -738,8 +754,7 @@ my_SSL_set_fd(Port *port, int fd)
SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
goto err;
}
- /* Use 'ptr' to store pointer to PGconn */
- bio->ptr = port;
+ BIO_set_data(bio, port);
BIO_set_fd(bio, fd, BIO_NOCLOSE);
SSL_set_bio(port->ssl, bio, bio);
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index d871612..12cab74 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -1617,15 +1617,19 @@ PQsslAttribute(PGconn *conn, const char *attribute_name)
* to retry; do we need to adopt their logic for that?
*/
-static bool my_bio_initialized = false;
-static BIO_METHOD my_bio_methods;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#define BIO_get_data(bio) (bio->ptr)
+#define BIO_set_data(bio, data) (bio->ptr = data)
+#endif
+
+static BIO_METHOD *my_bio_methods;
static int
my_sock_read(BIO *h, char *buf, int size)
{
int res;
- res = pqsecure_raw_read((PGconn *) h->ptr, buf, size);
+ res = pqsecure_raw_read((PGconn *) BIO_get_data(h), buf, size);
BIO_clear_retry_flags(h);
if (res < 0)
{
@@ -1655,7 +1659,7 @@ my_sock_write(BIO *h, const char *buf, int size)
{
int res;
- res = pqsecure_raw_write((PGconn *) h->ptr, buf, size);
+ res = pqsecure_raw_write((PGconn *) BIO_get_data(h), buf, size);
BIO_clear_retry_flags(h);
if (res <= 0)
{
@@ -1683,14 +1687,26 @@ my_sock_write(BIO *h, const char *buf, int size)
static BIO_METHOD *
my_BIO_s_socket(void)
{
- if (!my_bio_initialized)
+ if (!my_bio_methods)
{
- 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;
+ BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket();
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ my_bio_methods = BIO_meth_new(BIO_TYPE_SOCKET, "pgsocket");
+ 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_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));
+#else
+ my_bio_methods = malloc(sizeof(BIO_METHOD));
+ 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;
+ return my_bio_methods;
}
/* This should exactly match openssl's SSL_set_fd except for using my BIO */
@@ -1706,8 +1722,7 @@ my_SSL_set_fd(PGconn *conn, int fd)
SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
goto err;
}
- /* Use 'ptr' to store pointer to PGconn */
- bio->ptr = conn;
+ BIO_set_data(bio, conn);
SSL_set_bio(conn->ssl, bio, bio);
BIO_set_fd(bio, fd, BIO_NOCLOSE);
--
2.9.3