aboutsummaryrefslogtreecommitdiff
path: root/src/backend/libpq/be-secure-openssl.c
diff options
context:
space:
mode:
authorDaniel Gustafsson <dgustafsson@postgresql.org>2024-10-24 15:20:28 +0200
committerDaniel Gustafsson <dgustafsson@postgresql.org>2024-10-24 15:20:28 +0200
commit3d1ef3a15c3eb68dae44b94e89d04c422b26fc16 (patch)
treea710673741765cd033447a36f5e06005fa3fdc38 /src/backend/libpq/be-secure-openssl.c
parent6c66b7443cebf3ff09ea76416a20fb6bb1d32a52 (diff)
downloadpostgresql-3d1ef3a15c3eb68dae44b94e89d04c422b26fc16.tar.gz
postgresql-3d1ef3a15c3eb68dae44b94e89d04c422b26fc16.zip
Support configuring multiple ECDH curves
The ssl_ecdh_curve GUC only accepts a single value, but the TLS handshake can list multiple curves in the groups extension (the extension has been renamed to contain more than elliptic curves). This changes the GUC to accept a colon-separated list of curves. This commit also renames the GUC to ssl_groups to match the new nomenclature for the TLS extension. Original patch by Erica Zhang with additional hacking by me. Author: Erica Zhang <ericazhangy2021@qq.com> Author: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: Jacob Champion <jacob.champion@enterprisedb.com> Reviewed-by: Andres Freund <andres@anarazel.de> Reviewed-by: Peter Eisentraut <peter@eisentraut.org> Reviewed-by: Jelte Fennema-Nio <postgres@jeltef.nl> Discussion: https://postgr.es/m/tencent_063F89FA72CCF2E48A0DF5338841988E9809@qq.com
Diffstat (limited to 'src/backend/libpq/be-secure-openssl.c')
-rw-r--r--src/backend/libpq/be-secure-openssl.c56
1 files changed, 36 insertions, 20 deletions
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 9d503104be3..c8cd81d8537 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -76,6 +76,7 @@ static int alpn_cb(SSL *ssl,
void *userdata);
static bool initialize_dh(SSL_CTX *context, bool isServerStart);
static bool initialize_ecdh(SSL_CTX *context, bool isServerStart);
+static const char *SSLerrmessageExt(unsigned long ecode, const char *replacement);
static const char *SSLerrmessage(unsigned long ecode);
static char *X509_NAME_to_cstring(X509_NAME *name);
@@ -1409,36 +1410,51 @@ static bool
initialize_ecdh(SSL_CTX *context, bool isServerStart)
{
#ifndef OPENSSL_NO_ECDH
- EC_KEY *ecdh;
- int nid;
-
- nid = OBJ_sn2nid(SSLECDHCurve);
- if (!nid)
- {
- ereport(isServerStart ? FATAL : LOG,
- (errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve)));
- return false;
- }
-
- ecdh = EC_KEY_new_by_curve_name(nid);
- if (!ecdh)
+ if (SSL_CTX_set1_groups_list(context, SSLECDHCurve) != 1)
{
+ /*
+ * OpenSSL 3.3.0 introduced proper error messages for group parsing
+ * errors, earlier versions returns "no SSL error reported" which is
+ * far from helpful. For older versions, we replace with a better
+ * error message. Injecting the error into the OpenSSL error queue
+ * need APIs from OpenSSL 3.0.
+ */
ereport(isServerStart ? FATAL : LOG,
- (errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("ECDH: could not create key")));
+ errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("failed to set group names specified in ssl_groups: %s",
+ SSLerrmessageExt(ERR_get_error(),
+ _("No valid groups found"))),
+ errhint("Ensure that each group name is spelled correctly and supported by the installed version of OpenSSL"));
return false;
}
-
- SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
- SSL_CTX_set_tmp_ecdh(context, ecdh);
- EC_KEY_free(ecdh);
#endif
return true;
}
/*
+ * Obtain reason string for passed SSL errcode with replacement
+ *
+ * The error message supplied in replacement will be used in case the error
+ * code from OpenSSL is 0, else the error message from SSLerrmessage() will
+ * be returned.
+ *
+ * Not all versions of OpenSSL place an error on the queue even for failing
+ * operations, which will yield "no SSL error reported" by SSLerrmessage. This
+ * function can be used to ensure that a proper error message is displayed for
+ * versions reporting no error, while using the OpenSSL error via SSLerrmessage
+ * for versions where there is one.
+ */
+static const char *
+SSLerrmessageExt(unsigned long ecode, const char *replacement)
+{
+ if (ecode == 0)
+ return replacement;
+ else
+ return SSLerrmessage(ecode);
+}
+
+/*
* Obtain reason string for passed SSL errcode
*
* ERR_get_error() is used by caller to get errcode to pass here.