mirror of https://github.com/postgres/postgres
Add notBefore and notAfter to SSL cert info display
This adds the X509 attributes notBefore and notAfter to sslinfo as well as pg_stat_ssl to allow verifying and identifying the validity period of the current client certificate. OpenSSL has APIs for extracting notAfter and notBefore, but they are only supported in recent versions so we have to calculate the dates by hand in order to make this work for the older versions of OpenSSL that we still support. Original patch by Cary Huang with additional hacking by Jacob and myself. Author: Cary Huang <cary.huang@highgo.ca> Co-author: Jacob Champion <jacob.champion@enterprisedb.com> Co-author: Daniel Gustafsson <daniel@yesql.se> Discussion: https://postgr.es/m/182b8565486.10af1a86f158715.2387262617218380588@highgo.ca
This commit is contained in:
parent
b670b93a66
commit
6acb0a628e
|
@ -6,7 +6,7 @@ OBJS = \
|
|||
sslinfo.o
|
||||
|
||||
EXTENSION = sslinfo
|
||||
DATA = sslinfo--1.2.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
|
||||
DATA = sslinfo--1.2--1.3.sql sslinfo--1.2.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
|
||||
PGFILEDESC = "sslinfo - information about client SSL certificate"
|
||||
|
||||
ifdef USE_PGXS
|
||||
|
|
|
@ -26,6 +26,7 @@ install_data(
|
|||
'sslinfo--1.0--1.1.sql',
|
||||
'sslinfo--1.1--1.2.sql',
|
||||
'sslinfo--1.2.sql',
|
||||
'sslinfo--1.2--1.3.sql',
|
||||
'sslinfo.control',
|
||||
kwargs: contrib_data_args,
|
||||
)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/* contrib/sslinfo/sslinfo--1.2--1.3.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION sslinfo" to load this file. \quit
|
||||
|
||||
CREATE FUNCTION ssl_client_get_notbefore() RETURNS timestamptz
|
||||
AS 'MODULE_PATHNAME', 'ssl_client_get_notbefore'
|
||||
LANGUAGE C STRICT PARALLEL RESTRICTED;
|
||||
|
||||
CREATE FUNCTION ssl_client_get_notafter() RETURNS timestamptz
|
||||
AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
|
||||
LANGUAGE C STRICT PARALLEL RESTRICTED;
|
|
@ -14,10 +14,12 @@
|
|||
#include <openssl/asn1.h>
|
||||
|
||||
#include "access/htup_details.h"
|
||||
#include "common/int.h"
|
||||
#include "funcapi.h"
|
||||
#include "libpq/libpq-be.h"
|
||||
#include "miscadmin.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/timestamp.h"
|
||||
|
||||
/*
|
||||
* On Windows, <wincrypt.h> includes a #define for X509_NAME, which breaks our
|
||||
|
@ -34,6 +36,7 @@ PG_MODULE_MAGIC;
|
|||
|
||||
static Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName);
|
||||
static Datum ASN1_STRING_to_text(ASN1_STRING *str);
|
||||
static Datum ASN1_TIME_to_timestamptz(ASN1_TIME *time);
|
||||
|
||||
/*
|
||||
* Function context for data persisting over repeated calls.
|
||||
|
@ -225,6 +228,66 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Converts OpenSSL ASN1_TIME structure into timestamptz
|
||||
*
|
||||
* OpenSSL 1.0.2 doesn't expose a function to convert an ASN1_TIME to a tm
|
||||
* struct, it's only available in 1.1.1 and onwards. Instead we can ask for the
|
||||
* difference between the ASN1_TIME and a known timestamp and get the actual
|
||||
* timestamp that way. Until support for OpenSSL 1.0.2 is retired we have to do
|
||||
* it this way.
|
||||
*
|
||||
* Parameter: time - OpenSSL ASN1_TIME structure.
|
||||
* Returns Datum, which can be directly returned from a C language SQL
|
||||
* function.
|
||||
*/
|
||||
static Datum
|
||||
ASN1_TIME_to_timestamptz(ASN1_TIME *ASN1_cert_ts)
|
||||
{
|
||||
int days;
|
||||
int seconds;
|
||||
const char postgres_epoch[] = "20000101000000Z";
|
||||
ASN1_TIME *ASN1_epoch;
|
||||
int64 result_days;
|
||||
int64 result_secs;
|
||||
int64 result;
|
||||
|
||||
/* Create an epoch to compare against */
|
||||
ASN1_epoch = ASN1_TIME_new();
|
||||
if (!ASN1_epoch)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("could not allocate memory for ASN1 TIME structure")));
|
||||
|
||||
/* Calculate the diff from the epoch to the certificate timestamp */
|
||||
if (!ASN1_TIME_set_string(ASN1_epoch, postgres_epoch) ||
|
||||
!ASN1_TIME_diff(&days, &seconds, ASN1_epoch, ASN1_cert_ts))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("failed to read certificate validity")));
|
||||
|
||||
/*
|
||||
* Unlike when freeing other OpenSSL memory structures, there is no error
|
||||
* return on freeing ASN1 strings.
|
||||
*/
|
||||
ASN1_TIME_free(ASN1_epoch);
|
||||
|
||||
/*
|
||||
* Convert the reported date into usecs to be used as a TimestampTz. The
|
||||
* date should really not overflow an int64 but rather than trusting the
|
||||
* certificate we take overflow into consideration.
|
||||
*/
|
||||
if (pg_mul_s64_overflow(days, USECS_PER_DAY, &result_days) ||
|
||||
pg_mul_s64_overflow(seconds, USECS_PER_SEC, &result_secs) ||
|
||||
pg_add_s64_overflow(result_days, result_secs, &result))
|
||||
{
|
||||
return TimestampTzGetDatum(0);
|
||||
}
|
||||
|
||||
return TimestampTzGetDatum(result);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns specified field of client certificate distinguished name
|
||||
*
|
||||
|
@ -482,3 +545,35 @@ ssl_extension_info(PG_FUNCTION_ARGS)
|
|||
/* All done */
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns current client certificate notBefore timestamp in
|
||||
* timestamptz data type
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_client_get_notbefore);
|
||||
Datum
|
||||
ssl_client_get_notbefore(PG_FUNCTION_ARGS)
|
||||
{
|
||||
X509 *cert = MyProcPort->peer;
|
||||
|
||||
if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
|
||||
PG_RETURN_NULL();
|
||||
|
||||
return ASN1_TIME_to_timestamptz(X509_get_notBefore(cert));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns current client certificate notAfter timestamp in
|
||||
* timestamptz data type
|
||||
*/
|
||||
PG_FUNCTION_INFO_V1(ssl_client_get_notafter);
|
||||
Datum
|
||||
ssl_client_get_notafter(PG_FUNCTION_ARGS)
|
||||
{
|
||||
X509 *cert = MyProcPort->peer;
|
||||
|
||||
if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
|
||||
PG_RETURN_NULL();
|
||||
|
||||
return ASN1_TIME_to_timestamptz(X509_get_notAfter(cert));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# sslinfo extension
|
||||
comment = 'information about SSL certificates'
|
||||
default_version = '1.2'
|
||||
default_version = '1.3'
|
||||
module_pathname = '$libdir/sslinfo'
|
||||
relocatable = true
|
||||
|
|
|
@ -2292,6 +2292,26 @@ description | Waiting for a newly initialized WAL file to reach durable storage
|
|||
This field is truncated like <structfield>client_dn</structfield>.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>not_before</structfield> <type>text</type>
|
||||
</para>
|
||||
<para>
|
||||
Not before timestamp of the client certificate, or NULL if no client
|
||||
certificate was supplied.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>not_after</structfield> <type>text</type>
|
||||
</para>
|
||||
<para>
|
||||
Not after timestamp of the client certificate, or NULL if no client
|
||||
certificate was supplied.
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
|
|
@ -240,6 +240,36 @@ emailAddress
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>ssl_client_get_notbefore() returns timestamptz</function>
|
||||
<indexterm>
|
||||
<primary>ssl_client_get_notbefore</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Return the <structfield>not before</structfield> timestamp of the client
|
||||
certificate.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>ssl_client_get_notafter() returns timestamptz</function>
|
||||
<indexterm>
|
||||
<primary>ssl_client_get_notafter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Return the <structfield>not after</structfield> timestamp of the client
|
||||
certificate.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</sect2>
|
||||
|
||||
|
|
|
@ -992,7 +992,9 @@ CREATE VIEW pg_stat_ssl AS
|
|||
S.sslbits AS bits,
|
||||
S.ssl_client_dn AS client_dn,
|
||||
S.ssl_client_serial AS client_serial,
|
||||
S.ssl_issuer_dn AS issuer_dn
|
||||
S.ssl_issuer_dn AS issuer_dn,
|
||||
S.ssl_not_before AS not_before,
|
||||
S.ssl_not_after AS not_after
|
||||
FROM pg_stat_get_activity(NULL) AS S
|
||||
WHERE S.client_port IS NOT NULL;
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "common/int.h"
|
||||
#include "common/string.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "miscadmin.h"
|
||||
|
@ -36,6 +37,7 @@
|
|||
#include "tcop/tcopprot.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/timestamp.h"
|
||||
|
||||
/*
|
||||
* These SSL-related #includes must come after all system-provided headers.
|
||||
|
@ -72,6 +74,7 @@ static bool initialize_ecdh(SSL_CTX *context, bool isServerStart);
|
|||
static const char *SSLerrmessage(unsigned long ecode);
|
||||
|
||||
static char *X509_NAME_to_cstring(X509_NAME *name);
|
||||
static TimestampTz ASN1_TIME_to_timestamptz(ASN1_TIME *time);
|
||||
|
||||
static SSL_CTX *SSL_context = NULL;
|
||||
static bool SSL_initialized = false;
|
||||
|
@ -1430,6 +1433,24 @@ be_tls_get_peer_issuer_name(Port *port, char *ptr, size_t len)
|
|||
ptr[0] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
be_tls_get_peer_not_before(Port *port, TimestampTz *ptr)
|
||||
{
|
||||
if (port->peer)
|
||||
*ptr = ASN1_TIME_to_timestamptz(X509_get_notBefore(port->peer));
|
||||
else
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
void
|
||||
be_tls_get_peer_not_after(Port *port, TimestampTz *ptr)
|
||||
{
|
||||
if (port->peer)
|
||||
*ptr = ASN1_TIME_to_timestamptz(X509_get_notAfter(port->peer));
|
||||
else
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
void
|
||||
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
|
||||
{
|
||||
|
@ -1573,6 +1594,63 @@ X509_NAME_to_cstring(X509_NAME *name)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an ASN1_TIME to a Timestamptz. OpenSSL 1.0.2 doesn't expose a function
|
||||
* to convert an ASN1_TIME to a tm struct, it's only available in 1.1.1 and
|
||||
* onwards. Instead we can ask for the difference between the ASN1_TIME and a
|
||||
* known timestamp and get the actual timestamp that way. Until support for
|
||||
* OpenSSL 1.0.2 is retired we have to do it this way.
|
||||
*/
|
||||
static TimestampTz
|
||||
ASN1_TIME_to_timestamptz(ASN1_TIME *ASN1_cert_ts)
|
||||
{
|
||||
int days;
|
||||
int seconds;
|
||||
const char postgres_epoch[] = "20000101000000Z";
|
||||
ASN1_TIME *ASN1_epoch;
|
||||
int64 result_days;
|
||||
int64 result_seconds;
|
||||
int64 result;
|
||||
|
||||
/* Create an epoch to compare against */
|
||||
ASN1_epoch = ASN1_TIME_new();
|
||||
if (!ASN1_epoch)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("could not allocate memory for ASN1 TIME structure")));
|
||||
|
||||
/*
|
||||
* Calculate the diff from the epoch to the certificate timestamp.
|
||||
* POSTGRES_EPOCH_JDATE cannot be used here since OpenSSL needs an epoch
|
||||
* in the ASN.1 format.
|
||||
*/
|
||||
if (!ASN1_TIME_set_string(ASN1_epoch, postgres_epoch) ||
|
||||
!ASN1_TIME_diff(&days, &seconds, ASN1_epoch, ASN1_cert_ts))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("failed to read certificate validity")));
|
||||
|
||||
/*
|
||||
* Unlike when freeing other OpenSSL memory structures, there is no error
|
||||
* return on freeing ASN1 strings.
|
||||
*/
|
||||
ASN1_TIME_free(ASN1_epoch);
|
||||
|
||||
/*
|
||||
* Convert the reported date into usecs to be used as a TimestampTz. The
|
||||
* date should really not overflow an int64 but rather than trusting the
|
||||
* certificate we take overflow into consideration.
|
||||
*/
|
||||
if (pg_mul_s64_overflow(days, USECS_PER_DAY, &result_days) ||
|
||||
pg_mul_s64_overflow(seconds, USECS_PER_SEC, &result_seconds) ||
|
||||
pg_add_s64_overflow(result_seconds, result_days, &result))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert TLS protocol version GUC enum to OpenSSL values
|
||||
*
|
||||
|
|
|
@ -348,6 +348,8 @@ pgstat_bestart(void)
|
|||
be_tls_get_peer_subject_name(MyProcPort, lsslstatus.ssl_client_dn, NAMEDATALEN);
|
||||
be_tls_get_peer_serial(MyProcPort, lsslstatus.ssl_client_serial, NAMEDATALEN);
|
||||
be_tls_get_peer_issuer_name(MyProcPort, lsslstatus.ssl_issuer_dn, NAMEDATALEN);
|
||||
be_tls_get_peer_not_before(MyProcPort, &lsslstatus.ssl_not_before);
|
||||
be_tls_get_peer_not_after(MyProcPort, &lsslstatus.ssl_not_after);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -302,7 +302,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
pg_stat_get_activity(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#define PG_STAT_GET_ACTIVITY_COLS 31
|
||||
#define PG_STAT_GET_ACTIVITY_COLS 33
|
||||
int num_backends = pgstat_fetch_stat_numbackends();
|
||||
int curr_backend;
|
||||
int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
|
||||
|
@ -394,7 +394,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
|||
pfree(clipped_activity);
|
||||
|
||||
/* leader_pid */
|
||||
nulls[29] = true;
|
||||
nulls[31] = true;
|
||||
|
||||
proc = BackendPidGetProc(beentry->st_procpid);
|
||||
|
||||
|
@ -431,8 +431,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
|||
*/
|
||||
if (leader && leader->pid != beentry->st_procpid)
|
||||
{
|
||||
values[29] = Int32GetDatum(leader->pid);
|
||||
nulls[29] = false;
|
||||
values[31] = Int32GetDatum(leader->pid);
|
||||
nulls[31] = false;
|
||||
}
|
||||
else if (beentry->st_backendType == B_BG_WORKER)
|
||||
{
|
||||
|
@ -440,8 +440,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
|||
|
||||
if (leader_pid != InvalidPid)
|
||||
{
|
||||
values[29] = Int32GetDatum(leader_pid);
|
||||
nulls[29] = false;
|
||||
values[31] = Int32GetDatum(leader_pid);
|
||||
nulls[31] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -586,35 +586,45 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
|||
values[24] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn);
|
||||
else
|
||||
nulls[24] = true;
|
||||
|
||||
if (beentry->st_sslstatus->ssl_not_before != 0)
|
||||
values[25] = TimestampTzGetDatum(beentry->st_sslstatus->ssl_not_before);
|
||||
else
|
||||
nulls[25] = true;
|
||||
|
||||
if (beentry->st_sslstatus->ssl_not_after != 0)
|
||||
values[26] = TimestampTzGetDatum(beentry->st_sslstatus->ssl_not_after);
|
||||
else
|
||||
nulls[26] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
values[18] = BoolGetDatum(false); /* ssl */
|
||||
nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = true;
|
||||
nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = nulls[25] = nulls[26] = true;
|
||||
}
|
||||
|
||||
/* GSSAPI information */
|
||||
if (beentry->st_gss)
|
||||
{
|
||||
values[25] = BoolGetDatum(beentry->st_gssstatus->gss_auth); /* gss_auth */
|
||||
values[26] = CStringGetTextDatum(beentry->st_gssstatus->gss_princ);
|
||||
values[27] = BoolGetDatum(beentry->st_gssstatus->gss_enc); /* GSS Encryption in use */
|
||||
values[28] = BoolGetDatum(beentry->st_gssstatus->gss_delegation); /* GSS credentials
|
||||
values[27] = BoolGetDatum(beentry->st_gssstatus->gss_auth); /* gss_auth */
|
||||
values[28] = CStringGetTextDatum(beentry->st_gssstatus->gss_princ);
|
||||
values[29] = BoolGetDatum(beentry->st_gssstatus->gss_enc); /* GSS Encryption in use */
|
||||
values[30] = BoolGetDatum(beentry->st_gssstatus->gss_delegation); /* GSS credentials
|
||||
* delegated */
|
||||
}
|
||||
else
|
||||
{
|
||||
values[25] = BoolGetDatum(false); /* gss_auth */
|
||||
nulls[26] = true; /* No GSS principal */
|
||||
values[27] = BoolGetDatum(false); /* GSS Encryption not in
|
||||
values[27] = BoolGetDatum(false); /* gss_auth */
|
||||
nulls[28] = true; /* No GSS principal */
|
||||
values[29] = BoolGetDatum(false); /* GSS Encryption not in
|
||||
* use */
|
||||
values[28] = BoolGetDatum(false); /* GSS credentials not
|
||||
values[30] = BoolGetDatum(false); /* GSS credentials not
|
||||
* delegated */
|
||||
}
|
||||
if (beentry->st_query_id == 0)
|
||||
nulls[30] = true;
|
||||
nulls[32] = true;
|
||||
else
|
||||
values[30] = UInt64GetDatum(beentry->st_query_id);
|
||||
values[32] = UInt64GetDatum(beentry->st_query_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -644,6 +654,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
|||
nulls[28] = true;
|
||||
nulls[29] = true;
|
||||
nulls[30] = true;
|
||||
nulls[31] = true;
|
||||
nulls[32] = true;
|
||||
}
|
||||
|
||||
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
|
||||
|
|
|
@ -57,6 +57,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202403222
|
||||
#define CATALOG_VERSION_NO 202403223
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5440,9 +5440,9 @@
|
|||
proname => 'pg_stat_get_activity', prorows => '100', proisstrict => 'f',
|
||||
proretset => 't', provolatile => 's', proparallel => 'r',
|
||||
prorettype => 'record', proargtypes => 'int4',
|
||||
proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,text,numeric,text,bool,text,bool,bool,int4,int8}',
|
||||
proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
|
||||
proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc,gss_delegation,leader_pid,query_id}',
|
||||
proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,text,numeric,text,timestamptz,timestamptz,bool,text,bool,bool,int4,int8}',
|
||||
proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
|
||||
proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,ssl_not_before,ssl_not_after,gss_auth,gss_princ,gss_enc,gss_delegation,leader_pid,query_id}',
|
||||
prosrc => 'pg_stat_get_activity' },
|
||||
{ oid => '8403', descr => 'describe wait events',
|
||||
proname => 'pg_get_wait_events', procost => '10', prorows => '250',
|
||||
|
|
|
@ -294,6 +294,8 @@ extern const char *be_tls_get_cipher(Port *port);
|
|||
extern void be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len);
|
||||
extern void be_tls_get_peer_issuer_name(Port *port, char *ptr, size_t len);
|
||||
extern void be_tls_get_peer_serial(Port *port, char *ptr, size_t len);
|
||||
extern void be_tls_get_peer_not_before(Port *port, TimestampTz *ptr);
|
||||
extern void be_tls_get_peer_not_after(Port *port, TimestampTz *ptr);
|
||||
|
||||
/*
|
||||
* Get the server certificate hash for SCRAM channel binding type
|
||||
|
|
|
@ -61,6 +61,9 @@ typedef struct PgBackendSSLStatus
|
|||
char ssl_client_serial[NAMEDATALEN];
|
||||
|
||||
char ssl_issuer_dn[NAMEDATALEN];
|
||||
/* Certificate validity in postgres epoch format */
|
||||
TimestampTz ssl_not_before;
|
||||
TimestampTz ssl_not_after;
|
||||
} PgBackendSSLStatus;
|
||||
|
||||
/*
|
||||
|
|
|
@ -1763,7 +1763,7 @@ pg_stat_activity| SELECT s.datid,
|
|||
s.query_id,
|
||||
s.query,
|
||||
s.backend_type
|
||||
FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, gss_delegation, leader_pid, query_id)
|
||||
FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, ssl_not_before, ssl_not_after, gss_auth, gss_princ, gss_enc, gss_delegation, leader_pid, query_id)
|
||||
LEFT JOIN pg_database d ON ((s.datid = d.oid)))
|
||||
LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
|
||||
pg_stat_all_indexes| SELECT c.oid AS relid,
|
||||
|
@ -1883,7 +1883,7 @@ pg_stat_gssapi| SELECT pid,
|
|||
gss_princ AS principal,
|
||||
gss_enc AS encrypted,
|
||||
gss_delegation AS credentials_delegated
|
||||
FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, gss_delegation, leader_pid, query_id)
|
||||
FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, ssl_not_before, ssl_not_after, gss_auth, gss_princ, gss_enc, gss_delegation, leader_pid, query_id)
|
||||
WHERE (client_port IS NOT NULL);
|
||||
pg_stat_io| SELECT backend_type,
|
||||
object,
|
||||
|
@ -2086,7 +2086,7 @@ pg_stat_replication| SELECT s.pid,
|
|||
w.sync_priority,
|
||||
w.sync_state,
|
||||
w.reply_time
|
||||
FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, gss_delegation, leader_pid, query_id)
|
||||
FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, ssl_not_before, ssl_not_after, gss_auth, gss_princ, gss_enc, gss_delegation, leader_pid, query_id)
|
||||
JOIN pg_stat_get_wal_senders() w(pid, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag, sync_priority, sync_state, reply_time) ON ((s.pid = w.pid)))
|
||||
LEFT JOIN pg_authid u ON ((s.usesysid = u.oid)));
|
||||
pg_stat_replication_slots| SELECT s.slot_name,
|
||||
|
@ -2119,8 +2119,10 @@ pg_stat_ssl| SELECT pid,
|
|||
sslbits AS bits,
|
||||
ssl_client_dn AS client_dn,
|
||||
ssl_client_serial AS client_serial,
|
||||
ssl_issuer_dn AS issuer_dn
|
||||
FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, gss_delegation, leader_pid, query_id)
|
||||
ssl_issuer_dn AS issuer_dn,
|
||||
ssl_not_before AS not_before,
|
||||
ssl_not_after AS not_after
|
||||
FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, ssl_not_before, ssl_not_after, gss_auth, gss_princ, gss_enc, gss_delegation, leader_pid, query_id)
|
||||
WHERE (client_port IS NOT NULL);
|
||||
pg_stat_subscription| SELECT su.oid AS subid,
|
||||
su.subname,
|
||||
|
|
|
@ -538,8 +538,8 @@ command_like(
|
|||
"$common_connstr sslrootcert=invalid", '-c',
|
||||
"SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
|
||||
],
|
||||
qr{^pid,ssl,version,cipher,bits,client_dn,client_serial,issuer_dn\r?\n
|
||||
^\d+,t,TLSv[\d.]+,[\w-]+,\d+,_null_,_null_,_null_\r?$}mx,
|
||||
qr{^pid,ssl,version,cipher,bits,client_dn,client_serial,issuer_dn,not_before,not_after\r?\n
|
||||
^\d+,t,TLSv[\d.]+,[\w-]+,\d+,_null_,_null_,_null_,_null_,_null_\r?$}mx,
|
||||
'pg_stat_ssl view without client certificate');
|
||||
|
||||
# Test min/max SSL protocol versions.
|
||||
|
@ -740,10 +740,10 @@ command_like(
|
|||
"$common_connstr user=ssltestuser sslcert=ssl/client.crt "
|
||||
. sslkey('client.key'),
|
||||
'-c',
|
||||
"SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
|
||||
"SELECT ssl,version,cipher,bits,client_dn,client_serial,issuer_dn,not_before AT TIME ZONE 'UTC' AS not_before,not_after AT TIME ZONE 'UTC' AS not_after FROM pg_stat_ssl WHERE pid = pg_backend_pid()"
|
||||
],
|
||||
qr{^pid,ssl,version,cipher,bits,client_dn,client_serial,issuer_dn\r?\n
|
||||
^\d+,t,TLSv[\d.]+,[\w-]+,\d+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E\r?$}mx,
|
||||
qr{^ssl,version,cipher,bits,client_dn,client_serial,issuer_dn,not_before,not_after\r?\n
|
||||
^t,TLSv[\d.]+,[\w-]+,\d+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs,2023-06-29 01:01:01,2050-01-01 01:01:01\E\r?$}mx,
|
||||
'pg_stat_ssl with client certificate');
|
||||
|
||||
# client key with wrong permissions
|
||||
|
|
|
@ -165,6 +165,20 @@ $result = $node->safe_psql(
|
|||
connstr => $common_connstr);
|
||||
is($result, 't', "ssl_issuer_field() for commonName");
|
||||
|
||||
$result = $node->safe_psql(
|
||||
"certdb",
|
||||
"SELECT ssl_client_get_notbefore() = not_before, "
|
||||
. "not_before AT TIME ZONE 'UTC' = '2023-06-29 01:01:01' FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
|
||||
connstr => $common_connstr);
|
||||
is($result, 't|t', "ssl_client_get_notbefore() for not_before timestamp");
|
||||
|
||||
$result = $node->safe_psql(
|
||||
"certdb",
|
||||
"SELECT ssl_client_get_notafter() = not_after, "
|
||||
. "not_after AT TIME ZONE 'UTC' = '2050-01-01 01:01:01' FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
|
||||
connstr => $common_connstr);
|
||||
is($result, 't|t', "ssl_client_get_notafter() for not_after timestamp");
|
||||
|
||||
$result = $node->safe_psql(
|
||||
"certdb",
|
||||
"SELECT value, critical FROM ssl_extension_info() WHERE name = 'basicConstraints';",
|
||||
|
|
|
@ -6,6 +6,7 @@ ASN1_INTEGER
|
|||
ASN1_OBJECT
|
||||
ASN1_OCTET_STRING
|
||||
ASN1_STRING
|
||||
ASN1_TIME
|
||||
AV
|
||||
A_ArrayExpr
|
||||
A_Const
|
||||
|
|
Loading…
Reference in New Issue