aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/config.sgml25
-rw-r--r--src/backend/libpq/be-secure-openssl.c56
-rw-r--r--src/backend/utils/misc/guc.c1
-rw-r--r--src/backend/utils/misc/guc_tables.c6
-rw-r--r--src/backend/utils/misc/postgresql.conf.sample2
-rw-r--r--src/test/ssl/t/001_ssltests.pl12
-rw-r--r--src/test/ssl/t/SSL/Server.pm3
7 files changed, 72 insertions, 33 deletions
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 934ef5e4691..f8d862a6ce4 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1452,20 +1452,20 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
- <varlistentry id="guc-ssl-ecdh-curve" xreflabel="ssl_ecdh_curve">
- <term><varname>ssl_ecdh_curve</varname> (<type>string</type>)
+ <varlistentry id="guc-ssl-groups" xreflabel="ssl_groups">
+ <term><varname>ssl_groups</varname> (<type>string</type>)
<indexterm>
- <primary><varname>ssl_ecdh_curve</varname> configuration parameter</primary>
+ <primary><varname>ssl_groups</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Specifies the name of the curve to use in <acronym>ECDH</acronym> key
exchange. It needs to be supported by all clients that connect.
+ Multiple curves can be specified by using a colon-separated list.
It does not need to be the same curve used by the server's Elliptic
- Curve key.
- This parameter can only be set in the <filename>postgresql.conf</filename>
- file or on the server command line.
+ Curve key. This parameter can only be set in the
+ <filename>postgresql.conf</filename> file or on the server command line.
The default is <literal>prime256v1</literal>.
</para>
@@ -1475,9 +1475,16 @@ include_dir 'conf.d'
<literal>prime256v1</literal> (NIST P-256),
<literal>secp384r1</literal> (NIST P-384),
<literal>secp521r1</literal> (NIST P-521).
- The full list of available curves can be shown with the command
- <command>openssl ecparam -list_curves</command>. Not all of them
- are usable in <acronym>TLS</acronym> though.
+ An incomplete list of available groups can be shown with the command
+ <command>openssl ecparam -list_curves</command>. Not all of them are
+ usable with <acronym>TLS</acronym> though, and many supported group
+ names and aliases are omitted.
+ </para>
+
+ <para>
+ In <productname>PostgreSQL</productname> versions before 18.0 this
+ setting was named <literal>ssl_ecdh_curve</literal> and only accepted
+ a single value.
</para>
</listitem>
</varlistentry>
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.
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 507a5d329a3..90e91225b4e 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -190,6 +190,7 @@ static const unit_conversion time_unit_conversion_table[] =
static const char *const map_old_guc_names[] = {
"sort_mem", "work_mem",
"vacuum_mem", "maintenance_work_mem",
+ "ssl_ecdh_curve", "ssl_groups",
NULL
};
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 2c4cc8cd41b..859e6658e77 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -4656,9 +4656,9 @@ struct config_string ConfigureNamesString[] =
},
{
- {"ssl_ecdh_curve", PGC_SIGHUP, CONN_AUTH_SSL,
- gettext_noop("Sets the curve to use for ECDH."),
- NULL,
+ {"ssl_groups", PGC_SIGHUP, CONN_AUTH_SSL,
+ gettext_noop("Sets the group(s) to use for Diffie-Hellman key exchange."),
+ gettext_noop("Multiple groups can be specified using colon-separated list."),
GUC_SUPERUSER_ONLY
},
&SSLECDHCurve,
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 667e0dc40a2..204eab5f1a7 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -112,7 +112,7 @@
#ssl_key_file = 'server.key'
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
-#ssl_ecdh_curve = 'prime256v1'
+#ssl_groups = 'prime256v1'
#ssl_min_protocol_version = 'TLSv1.2'
#ssl_max_protocol_version = ''
#ssl_dh_params_file = ''
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 8eaf9deae79..131460a1fea 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -116,6 +116,18 @@ ssl_max_protocol_version=''});
$result = $node->restart(fail_ok => 1);
is($result, 1, 'restart succeeds with correct SSL protocol bounds');
+# Test parsing colon-separated groups. Resetting to a default value to clear
+# the error is fine since the call to switch_server_cert in the client side
+# tests will overwrite ssl_groups with a known set of groups.
+$node->append_conf('sslconfig.conf', qq{ssl_groups='bad:value'});
+my $log_size = -s $node->logfile;
+$result = $node->restart(fail_ok => 1);
+is($result, 0, 'restart fails with incorrect groups');
+ok($node->log_contains(qr/no SSL error reported/) == 0,
+ 'error message translated');
+$node->append_conf('ssl_config.conf', qq{ssl_groups='prime256v1'});
+$result = $node->restart(fail_ok => 1);
+
### Run client-side tests.
###
### Test that libpq accepts/rejects the connection correctly, depending
diff --git a/src/test/ssl/t/SSL/Server.pm b/src/test/ssl/t/SSL/Server.pm
index de06f6f242f..c1b25a4ebf6 100644
--- a/src/test/ssl/t/SSL/Server.pm
+++ b/src/test/ssl/t/SSL/Server.pm
@@ -300,6 +300,9 @@ sub switch_server_cert
ok(unlink($node->data_dir . '/sslconfig.conf'));
$node->append_conf('sslconfig.conf', "ssl=on");
$node->append_conf('sslconfig.conf', $backend->set_server_cert(\%params));
+ # use lists of ECDH curves for syntax testing
+ $node->append_conf('sslconfig.conf', 'ssl_groups=prime256v1:secp521r1');
+
$node->append_conf('sslconfig.conf',
"ssl_passphrase_command='" . $params{passphrase_cmd} . "'")
if defined $params{passphrase_cmd};