aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-secure-openssl.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2016-09-15 12:36:21 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2016-09-15 14:42:29 +0300
commit593d4e47db7af1a3a5dd6b6b1971f181b5566dbd (patch)
treedf6606b16f614ddbd1994f884216619410acd3e6 /src/interfaces/libpq/fe-secure-openssl.c
parentc99dd5bfed23d9787dcf7d00197c1ed42bcfdb02 (diff)
downloadpostgresql-593d4e47db7af1a3a5dd6b6b1971f181b5566dbd.tar.gz
postgresql-593d4e47db7af1a3a5dd6b6b1971f181b5566dbd.zip
Support OpenSSL 1.1.0.
Changes needed to build at all: - 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 can't embed them in other structs anymore. - RAND_SSLeay() -> RAND_OpenSSL() Changes that were needed to silence deprecation warnings, but were not strictly necessary: - RAND_pseudo_bytes() -> RAND_bytes(). - SSL_library_init() and OpenSSL_config() -> OPENSSL_init_ssl() - ASN1_STRING_data() -> ASN1_STRING_get0_data() - DH_generate_parameters() -> DH_generate_parameters() - Locking callbacks are not needed with OpenSSL 1.1.0 anymore. (Good riddance!) Also change references to SSLEAY_VERSION_NUMBER with OPENSSL_VERSION_NUMBER, for the sake of consistency. OPENSSL_VERSION_NUMBER has existed since time immemorial. Fix SSL test suite to work with OpenSSL 1.1.0. CA certificates must have the "CA:true" basic constraint extension now, or OpenSSL will refuse them. Regenerate the test certificates with that. The "openssl" binary, used to generate the certificates, is also now more picky, and throws an error if an X509 extension is specified in "req_extensions", but that section is empty. Backpatch to all supported branches, per popular demand. In back-branches, we still support OpenSSL 0.9.7 and above. OpenSSL 0.9.6 should still work too, but I didn't test it. In master, we only support 0.9.8 and above. Patch by Andreas Karlsson, with additional changes by me. Discussion: <20160627151604.GD1051@msg.df7cb.de>
Diffstat (limited to 'src/interfaces/libpq/fe-secure-openssl.c')
-rw-r--r--src/interfaces/libpq/fe-secure-openssl.c94
1 files changed, 73 insertions, 21 deletions
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index d8716128ec9..fe818251443 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -506,6 +506,9 @@ wildcard_certificate_match(const char *pattern, const char *string)
return 1;
}
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#define ASN1_STRING_get0_data ASN1_STRING_data
+#endif
/*
* Check if a name from a server's certificate matches the peer's hostname.
@@ -522,7 +525,7 @@ verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *name_entry,
{
int len;
char *name;
- unsigned char *namedata;
+ const unsigned char *namedata;
int result;
*store_name = NULL;
@@ -541,7 +544,7 @@ verify_peer_name_matches_certificate_name(PGconn *conn, ASN1_STRING *name_entry,
* There is no guarantee the string returned from the certificate is
* NULL-terminated, so make a copy that is.
*/
- namedata = ASN1_STRING_data(name_entry);
+ namedata = ASN1_STRING_get0_data(name_entry);
len = ASN1_STRING_length(name_entry);
name = malloc(len + 1);
if (name == NULL)
@@ -729,9 +732,10 @@ verify_peer_name_matches_certificate(PGconn *conn)
return found_match && !got_error;
}
-#ifdef ENABLE_THREAD_SAFETY
+#if defined(ENABLE_THREAD_SAFETY) && OPENSSL_VERSION_NUMBER < 0x10100000L
/*
- * Callback functions for OpenSSL internal locking
+ * Callback functions for OpenSSL internal locking. (OpenSSL 1.1.0
+ * does its own locking, and doesn't need these anymore.)
*/
static unsigned long
@@ -761,7 +765,7 @@ pq_lockingcallback(int mode, int n, const char *file, int line)
PGTHREAD_ERROR("failed to unlock mutex");
}
}
-#endif /* ENABLE_THREAD_SAFETY */
+#endif /* ENABLE_THREAD_SAFETY && OPENSSL_VERSION_NUMBER < 0x10100000L */
/*
* Initialize SSL system, in particular creating the SSL_context object
@@ -800,6 +804,7 @@ pgtls_init(PGconn *conn)
if (pthread_mutex_lock(&ssl_config_mutex))
return -1;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (pq_init_crypto_lib)
{
/*
@@ -840,15 +845,20 @@ pgtls_init(PGconn *conn)
CRYPTO_set_locking_callback(pq_lockingcallback);
}
}
+#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
#endif /* ENABLE_THREAD_SAFETY */
if (!SSL_context)
{
if (pq_init_ssl_lib)
{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
+#else
OPENSSL_config(NULL);
SSL_library_init();
SSL_load_error_strings();
+#endif
}
/*
@@ -897,12 +907,13 @@ pgtls_init(PGconn *conn)
* 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.
+ * 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)
{
-#ifdef ENABLE_THREAD_SAFETY
+#if defined(ENABLE_THREAD_SAFETY) && OPENSSL_VERSION_NUMBER < 0x10100000L
/* Mutex is created in initialize_ssl_system() */
if (pthread_mutex_lock(&ssl_config_mutex))
return;
@@ -1617,15 +1628,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 +1670,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 +1698,45 @@ 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
+ 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, "libpq socket");
+ if (!my_bio_methods)
+ return NULL;
+ /*
+ * As of this writing, these functions never fail. But check anyway, like
+ * OpenSSL's own examples do.
+ */
+ 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;
+ return my_bio_methods;
}
/* This should exactly match openssl's SSL_set_fd except for using my BIO */
@@ -1698,16 +1744,22 @@ static int
my_SSL_set_fd(PGconn *conn, int fd)
{
int ret = 0;
- BIO *bio = NULL;
+ BIO *bio;
+ BIO_METHOD *bio_method;
- bio = BIO_new(my_BIO_s_socket());
+ 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)
{
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);