From 28ed04b053247ecbcb1f14045cd16f98864f2488 Mon Sep 17 00:00:00 2001 From: Daniel Gustafsson Date: Tue, 26 May 2020 20:21:30 +0200 Subject: [PATCH 1/2] Compatibility with OpenSSL 3.0.0 OpenSSL 3.0.0 deprecates a set of functions used in libpq: SSL_CTX_load_verify_locations and X509_STORE_load_locations were replaced with individual calls for file and directory, so replace with the appropriate call since we only have configuration options for files. Usage of DH_check has been discouraged for a long time, and it was finally deprecated with no direct replacement. Instead implement a version using the EVP api which is the recommended alternative. u --- src/backend/libpq/be-secure-openssl.c | 81 +++++++++++++++++------- src/common/Makefile | 3 +- src/common/cert_openssl.c | 42 ++++++++++++ src/include/common/openssl.h | 6 ++ src/interfaces/libpq/fe-secure-openssl.c | 4 +- 5 files changed, 110 insertions(+), 26 deletions(-) create mode 100644 src/common/cert_openssl.c diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index 78a865d23b..32bdca30a1 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -266,7 +266,7 @@ be_tls_init(bool isServerStart) */ if (ssl_ca_file[0]) { - if (SSL_CTX_load_verify_locations(context, ssl_ca_file, NULL) != 1 || + if (SSL_CTX_load_verify_file(context, ssl_ca_file) != 1 || (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL) { ereport(isServerStart ? FATAL : LOG, @@ -289,7 +289,7 @@ be_tls_init(bool isServerStart) if (cvstore) { /* Set the flags to check against the complete CRL chain */ - if (X509_STORE_load_locations(cvstore, ssl_crl_file, NULL) == 1) + if (X509_STORE_load_file(cvstore, ssl_crl_file) == 1) { X509_STORE_set_flags(cvstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); @@ -817,7 +817,6 @@ load_dh_file(char *filename, bool isServerStart) { FILE *fp; DH *dh = NULL; - int codes; /* attempt to open file. It's not an error if it doesn't exist. */ if ((fp = AllocateFile(filename, "r")) == NULL) @@ -841,30 +840,66 @@ load_dh_file(char *filename, bool isServerStart) return NULL; } - /* make sure the DH parameters are usable */ - if (DH_check(dh, &codes) == 0) +#if OPENSSL_VERSION_MAJOR < 3 { - ereport(isServerStart ? FATAL : LOG, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("invalid DH parameters: %s", - SSLerrmessage(ERR_get_error())))); - return NULL; - } - if (codes & DH_CHECK_P_NOT_PRIME) - { - ereport(isServerStart ? FATAL : LOG, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("invalid DH parameters: p is not prime"))); - return NULL; + int codes; + + /* make sure the DH parameters are usable */ + if (DH_check(dh, &codes) == 0) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("invalid DH parameters: %s", + SSLerrmessage(ERR_get_error())))); + return NULL; + } + if (codes & DH_CHECK_P_NOT_PRIME) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("invalid DH parameters: p is not prime"))); + return NULL; + } + if ((codes & DH_NOT_SUITABLE_GENERATOR) && + (codes & DH_CHECK_P_NOT_SAFE_PRIME)) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("invalid DH parameters: neither suitable generator or safe prime"))); + return NULL; + } } - if ((codes & DH_NOT_SUITABLE_GENERATOR) && - (codes & DH_CHECK_P_NOT_SAFE_PRIME)) +#else { - ereport(isServerStart ? FATAL : LOG, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("invalid DH parameters: neither suitable generator or safe prime"))); - return NULL; + EVP_PKEY *pkey; + EVP_PKEY_CTX *pkey_ctx = NULL; + unsigned long err = 0; + + pkey = EVP_PKEY_new(); + + if (!EVP_PKEY_set1_DH(pkey, dh)) + err = ERR_get_error(); + else + { + pkey_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + + if (!EVP_PKEY_param_check(pkey_ctx)) + err = ERR_get_error(); + } + + EVP_PKEY_CTX_free(pkey_ctx); + EVP_PKEY_free(pkey); + + if (err) + { + ereport(isServerStart ? FATAL : LOG, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("invalid DH parameters: %s", + SSLerrmessage(err)))); + return NULL; + } } +#endif return dh; } diff --git a/src/common/Makefile b/src/common/Makefile index d0be882cca..482561f63e 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -80,7 +80,8 @@ OBJS_COMMON = \ ifeq ($(with_openssl),yes) OBJS_COMMON += \ protocol_openssl.o \ - sha2_openssl.o + sha2_openssl.o \ + cert_openssl.o else OBJS_COMMON += sha2.o endif diff --git a/src/common/cert_openssl.c b/src/common/cert_openssl.c new file mode 100644 index 0000000000..2149e7eb36 --- /dev/null +++ b/src/common/cert_openssl.c @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- + * + * protocol_openssl.c + * OpenSSL certificate functionality shared between frontend and backend + * + * This should only be used if code is compiled with OpenSSL support. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/cert_openssl.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include "common/openssl.h" + +/* + * SSL_CTX_load_verify_locations and X509_STORE_load_locations were deprecated + * in OpenSSL 3.0.0 and replaced by their new _file counterparts. Provide + * implementations of the replacement for OpenSSL versions 1.0.1 through 1.1.1 + * where they are missing. + */ +#if OPENSSL_VERSION_MAJOR < 3 +int +SSL_CTX_load_verify_file(SSL_CTX *ctx, const char *CAfile) +{ + return SSL_CTX_load_verify_locations(ctx, CAfile, NULL); +} +int +X509_STORE_load_file(X509_STORE *ctx, const char *file) +{ + return X509_STORE_load_locations(ctx, file, NULL); +} +#endif diff --git a/src/include/common/openssl.h b/src/include/common/openssl.h index 47fa129994..d5dc2910bf 100644 --- a/src/include/common/openssl.h +++ b/src/include/common/openssl.h @@ -23,6 +23,12 @@ extern int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version); extern int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version); #endif +/* src/common/cert_openssl.c */ +#if OPENSSL_VERSION_MAJOR < 3 +extern int SSL_CTX_load_verify_file(SSL_CTX *ctx, const char *CAfile); +int X509_STORE_load_file(X509_STORE *ctx, const char *file); +#endif + #endif #endif /* COMMON_OPENSSL_H */ diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index 2d813ef5f9..a1ad181976 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -922,7 +922,7 @@ initialize_SSL(PGconn *conn) { X509_STORE *cvstore; - if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1) + if (SSL_CTX_load_verify_file(SSL_context, fnbuf) != 1) { char *err = SSLerrmessage(ERR_get_error()); @@ -945,7 +945,7 @@ initialize_SSL(PGconn *conn) /* Set the flags to check against the complete CRL chain */ if (fnbuf[0] != '\0' && - X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1) + X509_STORE_load_file(cvstore, fnbuf) == 1) { X509_STORE_set_flags(cvstore, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); -- 2.21.1 (Apple Git-122.3)