Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vt85M-004Uwm-0T for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Feb 2026 17:45:08 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vt85J-0053sd-20 for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Feb 2026 17:45:05 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from <9erthalion6@gmail.com>) id 1vt85J-0053sV-0e for pgsql-hackers@lists.postgresql.org; Thu, 19 Feb 2026 17:45:05 +0000 Received: from mail-ed1-x536.google.com ([2a00:1450:4864:20::536]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from <9erthalion6@gmail.com>) id 1vt85F-00000000AVG-2gq9 for pgsql-hackers@postgresql.org; Thu, 19 Feb 2026 17:45:03 +0000 Received: by mail-ed1-x536.google.com with SMTP id 4fb4d7f45d1cf-658b6757f7fso2364083a12.1 for ; Thu, 19 Feb 2026 09:45:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1771523101; x=1772127901; darn=postgresql.org; h=content-disposition:mime-version:message-id:subject:to:from:date :from:to:cc:subject:date:message-id:reply-to; bh=IwXvZK8vK5jhyml+aTJZZnjSx9KUvfQTpy8Zd8DHK3U=; b=hXjbEjO4W/m4sBWNwfRRQPHPrk0MyWMrFr9DK03fp1OjF29fmXGVo5gaDu+5XTJrk5 gQ+xV1Uuexpw6lPFJlKXojrIqFzNKqlCLzAZd+BztWykpB3WZJeyD3dQ+kAAiUQjkOxx 1H7aEA796X+P7zq/awsnWAFYppa68sMHulPHX3RwLFUw1kv9Jieg14wvBSPEw5s527hi RsA8xvOE9pFhRvUKpouYtoEBKwsqLo9mRiwqwRPvK36XHtr4d3+PA5hmBNh9Xn7hg3GH +tVeadNkx9x6g1F/F2aAnsyHiZwhrt/9+VmVcUnj01x6piwzet/jUbRit6Xe7whmClt2 ot5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771523101; x=1772127901; h=content-disposition:mime-version:message-id:subject:to:from:date :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=IwXvZK8vK5jhyml+aTJZZnjSx9KUvfQTpy8Zd8DHK3U=; b=weEah8Wn6XXPHbGZOriimJ1DY31qGFqpDnSv4pZizyhGq53UMEPN5W9pcnEEOLvpwk /1PvdPKo4jDT7GlJYeX3xImnHrunXrZ6b7adlrDBf9BWVNNO7TSv586iSbYtJrsDzrks Xk5n8cV44UG/1JLZ2IIKTJ83DOb3qEw1fv6dYz5BSZUojIZNr+V9tNIhmONNV5WB/C3p w5fE6GwkF3HJTrrHmOSHjiZbVK8RlxWX8jJcxb1ZYw/pFNapG1HqG0CGITmOwhuMeraW +gl+ZErfD1GtPCaZo6PduETgIztjKL+o8f4MP+0WatEBiR+UmOGuxRLgJa7fY+T9CTmg RvLw== X-Gm-Message-State: AOJu0YxI6FekjeCP+nxUWvcUQ0CtPJd7/Le5V/jP/+I5U9JiVBMgDELo xnXpY8T7EKOP0qRdwSE6ZFIEOHRoIUhLlHgvb/smzSyrRprdSLsZxYQJOp0zEA== X-Gm-Gg: AZuq6aJzb2o8SCBsb60QHpQFa3bOGdoBurjNI61iOoE1lWoNSLXFHJ2jrbYmC8uIeF9 GiOTzW82gerMPzDcO17h9roreGMxMuCGPywFzon5eQmAX//tAHc/8Yo+jScrb8YE4fsmIrKcEyh Twcj67vJ4XO9HddluwBYvIKS472yqDz3Mv4K0u3bcxdhdm+n9PeIpIC6jgl2yItP8k410E9GrX8 l+QXoxJlwvlp3exf7Wyfosy74icgIzzBfSXfNIheNfLAR82EseOycmf9EyS8buQWIPO2aXZ5EmF M0tIV6iZuOuhL9k8enkGbwUohaUzMmKsr1JN2Be34019ZTRB5HOFP+64n54vmDfGyh8ldmg6G+S 2LaNhieKqxjzGEs+xs8bOprWqwquO0Vsh3G3s5jT5ZGf0Rs1OrhqO8eFRmEi9oSpmC+avDiGxSS ChF9NsjBVHGDLkn8Vw1UDt4WxqnoGL6I0b9ahf5tFUnzvaoFr/6tW/rS/T+qan6ef7VOZIHD+zA NVloS4AmMbcYFFL/Y43A/+yA7B83RpulQ+C X-Received: by 2002:aa7:d490:0:b0:659:9068:9786 with SMTP id 4fb4d7f45d1cf-65e4f7619c7mr1254489a12.10.1771523101057; Thu, 19 Feb 2026 09:45:01 -0800 (PST) Received: from ddolgov-thinkpadt14sgen1.rmtde.csb (dslb-002-207-075-089.002.207.pools.vodafone-ip.de. [2.207.75.89]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-65bad29d4basm4051101a12.12.2026.02.19.09.44.58 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 19 Feb 2026 09:45:00 -0800 (PST) Date: Thu, 19 Feb 2026 18:44:57 +0100 From: Dmitry Dolgov <9erthalion6@gmail.com> To: pgsql-hackers@postgresql.org Subject: Add ssl_(supported|shared)_groups to sslinfo Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="ymr2ng6a3l6bfm2s" Content-Disposition: inline List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --ymr2ng6a3l6bfm2s Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, I've been experimenting with ssl recently, and found it's useful to have more information exposed via contrib/sslinfo, in particular ssl_supported_groups and ssl_shared_groups to show TLS groups extension. I think it makes sense to add this, hence the patch. Any thoughts? --ymr2ng6a3l6bfm2s Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v1-0001-contrib-sslinfo-Add-ssl_-supported-shared-_groups.patch" From 40b40a4f6456832a595e4371698e2003ede5fcbf Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthalion6@gmail.com> Date: Thu, 19 Feb 2026 16:33:17 +0100 Subject: [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Add new functions to sslinfo to show TLS groups extension, both supported and shared. It's useful for identifying what's being used and supported, e.g. which key share is being negotiated. Few examples, for openssl 3.2.4: =# select ssl_shared_groups(); ssl_shared_groups ------------------- x25519:[...] =# select ssl_supported_groups(); ssl_supported_groups -------------------------------------- x25519:[...] And the same for openssl 3.5 with different defaults: =# select ssl_shared_groups(); ssl_shared_groups --------------------------------- X25519MLKEM768:[...] =# select ssl_supported_groups(); ssl_supported_groups ------------------------------------- X25519MLKEM768:[...] Do not add those functions into the pg_ssl_stats, because they could become quite large, bloating PgBackendSSLStatus. The implementation is inspired by ssl_print_groups from openssl. --- contrib/sslinfo/Makefile | 2 +- contrib/sslinfo/meson.build | 3 +- contrib/sslinfo/sslinfo--1.2--1.3.sql | 12 ++++++ contrib/sslinfo/sslinfo--1.3.sql | 56 ++++++++++++++++++++++++++ contrib/sslinfo/sslinfo.c | 31 ++++++++++++++ contrib/sslinfo/sslinfo.control | 2 +- src/backend/libpq/be-secure-openssl.c | 58 +++++++++++++++++++++++++++ src/include/libpq/libpq-be.h | 2 + 8 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 contrib/sslinfo/sslinfo--1.2--1.3.sql create mode 100644 contrib/sslinfo/sslinfo--1.3.sql diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile index 14305594e2d..d278f02c093 100644 --- a/contrib/sslinfo/Makefile +++ b/contrib/sslinfo/Makefile @@ -6,7 +6,7 @@ OBJS = \ sslinfo.o EXTENSION = sslinfo -DATA = sslinfo--1.2.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql +DATA = sslinfo--1.3.sql sslinfo--1.2--1.3.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql PGFILEDESC = "sslinfo - information about client SSL certificate" ifdef USE_PGXS diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build index 6e9cb96430a..0258813dde7 100644 --- a/contrib/sslinfo/meson.build +++ b/contrib/sslinfo/meson.build @@ -25,7 +25,8 @@ contrib_targets += sslinfo install_data( 'sslinfo--1.0--1.1.sql', 'sslinfo--1.1--1.2.sql', - 'sslinfo--1.2.sql', + 'sslinfo--1.2--1.3.sql', + 'sslinfo--1.3.sql', 'sslinfo.control', kwargs: contrib_data_args, ) diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql new file mode 100644 index 00000000000..d2cea79faa7 --- /dev/null +++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql @@ -0,0 +1,12 @@ +/* contrib/sslinfo/sslinfo--1.2--1.3.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION sslinfo UPDATE TO '1.3'" to load this file. \quit + +CREATE FUNCTION ssl_supported_groups() RETURNS text +AS 'MODULE_PATHNAME', 'ssl_supported_groups' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_shared_groups() RETURNS text +AS 'MODULE_PATHNAME', 'ssl_shared_groups' +LANGUAGE C STRICT PARALLEL RESTRICTED; diff --git a/contrib/sslinfo/sslinfo--1.3.sql b/contrib/sslinfo/sslinfo--1.3.sql new file mode 100644 index 00000000000..98b51900959 --- /dev/null +++ b/contrib/sslinfo/sslinfo--1.3.sql @@ -0,0 +1,56 @@ +/* contrib/sslinfo/sslinfo--1.3.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION sslinfo" to load this file. \quit + +CREATE FUNCTION ssl_client_serial() RETURNS numeric +AS 'MODULE_PATHNAME', 'ssl_client_serial' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_is_used() RETURNS boolean +AS 'MODULE_PATHNAME', 'ssl_is_used' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_version() RETURNS text +AS 'MODULE_PATHNAME', 'ssl_version' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_cipher() RETURNS text +AS 'MODULE_PATHNAME', 'ssl_cipher' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_client_cert_present() RETURNS boolean +AS 'MODULE_PATHNAME', 'ssl_client_cert_present' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_client_dn_field(text) RETURNS text +AS 'MODULE_PATHNAME', 'ssl_client_dn_field' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_issuer_field(text) RETURNS text +AS 'MODULE_PATHNAME', 'ssl_issuer_field' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_client_dn() RETURNS text +AS 'MODULE_PATHNAME', 'ssl_client_dn' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_issuer_dn() RETURNS text +AS 'MODULE_PATHNAME', 'ssl_issuer_dn' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_supported_groups() RETURNS text +AS 'MODULE_PATHNAME', 'ssl_supported_groups' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION ssl_shared_groups() RETURNS text +AS 'MODULE_PATHNAME', 'ssl_shared_groups' +LANGUAGE C STRICT PARALLEL RESTRICTED; + +CREATE FUNCTION +ssl_extension_info(OUT name text, + OUT value text, + OUT critical boolean +) RETURNS SETOF record +AS 'MODULE_PATHNAME', 'ssl_extension_info' +LANGUAGE C STRICT PARALLEL RESTRICTED; diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c index 2b9eb90b093..3efdca6d6bc 100644 --- a/contrib/sslinfo/sslinfo.c +++ b/contrib/sslinfo/sslinfo.c @@ -88,6 +88,37 @@ ssl_cipher(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring_to_text(cipher)); } +PG_FUNCTION_INFO_V1(ssl_supported_groups); +Datum +ssl_supported_groups(PG_FUNCTION_ARGS) +{ + const char *groups; + + if (!MyProcPort->ssl_in_use) + PG_RETURN_NULL(); + + groups = be_tls_get_supported_groups(MyProcPort); + if (groups == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(cstring_to_text(groups)); +} + +PG_FUNCTION_INFO_V1(ssl_shared_groups); +Datum +ssl_shared_groups(PG_FUNCTION_ARGS) +{ + const char *groups; + + if (!MyProcPort->ssl_in_use) + PG_RETURN_NULL(); + + groups = be_tls_get_shared_groups(MyProcPort); + if (groups == NULL) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(cstring_to_text(groups)); +} /* * Indicates whether current client provided a certificate diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control index c7754f924cf..b53e95b7da8 100644 --- a/contrib/sslinfo/sslinfo.control +++ b/contrib/sslinfo/sslinfo.control @@ -1,5 +1,5 @@ # sslinfo extension comment = 'information about SSL certificates' -default_version = '1.2' +default_version = '1.3' module_pathname = '$libdir/sslinfo' relocatable = true diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index 4da6ac22ff9..b134fc53f5f 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -51,6 +51,8 @@ #endif #include +#define SSL_SUPPORTED_GROUPS 0 +#define SSL_SHARED_GROUPS 1 /* default init hook can be overridden by a shared library */ static void default_openssl_tls_init(SSL_CTX *context, bool isServerStart); @@ -1560,6 +1562,62 @@ be_tls_get_cipher(Port *port) return NULL; } +static const char * +be_tls_get_groups_internal(Port *port, int type) +{ + if (port->ssl) + { + int i, ngroups, *groups, nid; + StringInfoData str; + + if (type == SSL_SUPPORTED_GROUPS) + ngroups = SSL_get1_groups(port->ssl, NULL); + else + ngroups = SSL_get_shared_group(port->ssl, -1); + + if (ngroups <= 0) + return NULL; + + groups = palloc(ngroups * sizeof(*groups)); + initStringInfo(&str); + + if (type == SSL_SUPPORTED_GROUPS) + SSL_get1_groups(port->ssl, groups); + + for (i = 0; i < ngroups; i++) + { + const char *name; + + if (i) + appendStringInfo(&str, ":"); + + if (type == SSL_SUPPORTED_GROUPS) + nid = groups[i]; + else + nid = SSL_get_shared_group(port->ssl, i); + + name = SSL_group_to_name(port->ssl, nid); + appendStringInfoString(&str, ((name != NULL) ? name : "(null)")); + } + + return str.data; + } + else + return NULL; +} + +const char * +be_tls_get_supported_groups(Port *port) +{ + return be_tls_get_groups_internal(port, SSL_SUPPORTED_GROUPS); +} + +const char * +be_tls_get_shared_groups(Port *port) +{ + return be_tls_get_groups_internal(port, SSL_SHARED_GROUPS); +} + void be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len) { diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index 921b2daa4ff..23e11fcb89d 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -317,6 +317,8 @@ extern ssize_t be_tls_write(Port *port, const void *ptr, size_t len, int *waitfo extern int be_tls_get_cipher_bits(Port *port); extern const char *be_tls_get_version(Port *port); extern const char *be_tls_get_cipher(Port *port); +extern const char *be_tls_get_supported_groups(Port *port); +extern const char *be_tls_get_shared_groups(Port *port); extern void be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len); extern void be_tls_get_peer_issuer_name(Port *port, char *ptr, size_t len); extern void be_tls_get_peer_serial(Port *port, char *ptr, size_t len); base-commit: 5b93a5987bd704d2363295eee919eee45f84c286 -- 2.52.0 --ymr2ng6a3l6bfm2s--