diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2016-09-15 12:55:38 +0300 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2016-09-15 12:55:38 +0300 |
commit | fcd93e4af943fc444a5928355c9471d36f077538 (patch) | |
tree | 532e9bd4568ee2c7d8157a788bf92a7433841c34 /src/backend/libpq/be-secure-openssl.c | |
parent | 18ae680632b5c7a1550a768f1a4dc8e31b08215d (diff) | |
download | postgresql-fcd93e4af943fc444a5928355c9471d36f077538.tar.gz postgresql-fcd93e4af943fc444a5928355c9471d36f077538.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 9.5 and 9.6, per popular demand. The file structure was
somewhat different in earlier branches, so I didn't bother to go further
than that. 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/backend/libpq/be-secure-openssl.c')
-rw-r--r-- | src/backend/libpq/be-secure-openssl.c | 101 |
1 files changed, 84 insertions, 17 deletions
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index f6adb155c6e..9ffb5af05e7 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -53,7 +53,7 @@ #include <openssl/ssl.h> #include <openssl/dh.h> -#if SSLEAY_VERSION_NUMBER >= 0x0907000L +#if OPENSSL_VERSION_NUMBER >= 0x0907000L #include <openssl/conf.h> #endif #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH) @@ -74,6 +74,7 @@ static int my_SSL_set_fd(Port *port, int fd); 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); @@ -166,11 +167,15 @@ be_tls_init(void) if (!SSL_context) { -#if SSLEAY_VERSION_NUMBER >= 0x0907000L +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); +#else +#if OPENSSL_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 @@ -673,8 +678,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) @@ -683,7 +692,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) { @@ -703,7 +712,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) { @@ -720,14 +729,41 @@ 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, "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; + return my_bio_methods; } /* This should exactly match openssl's SSL_set_fd except for using my BIO */ @@ -735,17 +771,23 @@ static int my_SSL_set_fd(Port *port, 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 = port; + BIO_set_data(bio, port); BIO_set_fd(bio, fd, BIO_NOCLOSE); SSL_set_bio(port->ssl, bio, bio); @@ -840,6 +882,31 @@ load_dh_buffer(const char *buffer, size_t len) } /* + * 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. @@ -908,7 +975,7 @@ tmp_dh_cb(SSL *s, int is_export, int keylength) ereport(DEBUG2, (errmsg_internal("DH: generating parameters (%d bits)", keylength))); - r = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL); + r = generate_dh_parameters(keylength, DH_GENERATOR_2); } return r; |