agora inbox for pgsql-hackers@postgresql.org
help / color / mirror / Atom feed[PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
285+ messages / 2 participants
[nested] [flat]
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups
@ 2026-02-19 15:33 Dmitrii Dolgov <9erthalion6@gmail.com>
0 siblings, 0 replies; 285+ messages in thread
From: Dmitrii Dolgov @ 2026-02-19 15:33 UTC (permalink / raw)
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 <openssl/x509v3.h>
+#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--
^ permalink raw reply [nested|flat] 285+ messages in thread
* [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly
@ 2026-07-03 10:47 Álvaro Herrera <alvherre@kurilemu.de>
0 siblings, 0 replies; 285+ messages in thread
From: Álvaro Herrera @ 2026-07-03 10:47 UTC (permalink / raw)
We were skipping a bunch of things that are mostly unnecessary for
REPACK. However, one thing that seems would be better to pass closer to
truth, is the updatedCols bitmapset in the range table entry for the
repacked table. Cons up an RTE and install it into the EState.
This only has an effect on btree indexes, because certain operations are
optimized in the case of unchanged columns; and even then, correctnesss
is not being compromised.
The values we pass after this commit are not fully trustworthy either,
because we simply say "all columns were updated" for all insert/updates,
regardless of whether their values were actually modified or not.
However, this way we err to the side of caution rather than to the
opposite direction as we were originally doing. This could be refined
in the future, but there's a trade-off: determining whether the column
was in fact updated could be expensive.
Author: Antonin Houska <ah@cybertec.at>
Reviewed-by: Ewan Young <kdbase.hack@gmail.com>
Backpatch-through: 19
Discussion: https://postgr.es/m/18222.1782126731@localhost
---
src/backend/commands/repack.c | 57 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 83a49afe7e1..faa07d1a118 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -63,6 +63,7 @@
#include "libpq/pqmq.h"
#include "miscadmin.h"
#include "optimizer/optimizer.h"
+#include "parser/parse_relation.h"
#include "pgstat.h"
#include "replication/logicalrelation.h"
#include "storage/bufmgr.h"
@@ -3019,8 +3020,60 @@ initialize_change_context(ChangeContext *chgcxt,
/* Only initialize fields needed by ExecInsertIndexTuples(). */
chgcxt->cc_estate = CreateExecutorState();
- chgcxt->cc_rri = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- InitResultRelInfo(chgcxt->cc_rri, relation, 0, 0, 0);
+ /*
+ * Set up a range table for the executor, containing our repacked table as
+ * its only member.
+ */
+ {
+ RangeTblEntry *rte;
+ TupleDesc desc = RelationGetDescr(relation);
+ List *perminfos = NIL;
+ Bitmapset *updatedCols = NULL;
+ RTEPermissionInfo *perminfo;
+
+ /*
+ * For our use, the RTE only needs to have perminfoindex initialized,
+ * but there's no reason to not set the fields whose values we have at
+ * hand.
+ */
+ rte = makeNode(RangeTblEntry);
+ rte->rtekind = RTE_RELATION;
+ rte->relid = RelationGetRelid(relation);
+ rte->relkind = RelationGetForm(relation)->relkind;
+ /* Create the RTEPermissionInfo instance (and set ->perminfoindex). */
+ addRTEPermissionInfo(&perminfos, rte);
+
+ /*
+ * Initialize updatedCols to show that all columns are updated. This
+ * is of course not necessarily true, and we cannot know this early;
+ * but this is only used by ExecInsertIndexTuples to flag index
+ * updates with no logical value changes, so if it's wrong, nothing
+ * terribly bad happens. We may want to improve this someday though.
+ *
+ * Don't claim that dropped columns are changed though.
+ */
+ for (int i = 0; i < desc->natts; i++)
+ {
+ CompactAttribute *attr = TupleDescCompactAttr(desc, i);
+
+ if (attr->attisdropped)
+ continue;
+ updatedCols = bms_add_member(updatedCols,
+ i + 1 - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* install updatedCols in the right place */
+ perminfo = getRTEPermissionInfo(perminfos, rte);
+ perminfo->updatedCols = updatedCols;
+
+ /* finally we can initialize the range table proper */
+ ExecInitRangeTable(chgcxt->cc_estate, list_make1(rte), perminfos,
+ bms_make_singleton(1));
+ }
+
+ /* Set up our ResultRelInfo to use for index updates */
+ chgcxt->cc_rri = makeNode(ResultRelInfo);
+ InitResultRelInfo(chgcxt->cc_rri, relation, 1, NULL, 0);
ExecOpenIndices(chgcxt->cc_rri, false);
/*
--
2.47.3
--pi6rmivyoaehyqn6--
^ permalink raw reply [nested|flat] 285+ messages in thread
end of thread, other threads:[~2026-07-03 10:47 UTC | newest]
Thread overview: 285+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-02-19 15:33 [PATCH v1] contrib/sslinfo: Add ssl_(supported|shared)_groups Dmitrii Dolgov <9erthalion6@gmail.com>
2026-07-03 10:47 [PATCH] REPACK CONCURRENTLY: Initialize the range table more honestly Álvaro Herrera <alvherre@kurilemu.de>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox