sslinfo extension - add notbefore and notafter timestamps
Hello
I noticed that sslinfo extension does not have functions to return current client certificate's notbefore and notafter timestamps which are also quite important attributes in a X509 certificate. The attached patch adds 2 functions to get notbefore and notafter timestamps from the currently connected client certificate.
thank you!
Cary Huang
-------------
HighGo Software Inc. (Canada)
mailto:cary.huang@highgo.ca
Attachments:
v1-0001-sslinfo-add-notbefore-and-notafter-timestamps.patchapplication/octet-stream; name=v1-0001-sslinfo-add-notbefore-and-notafter-timestamps.patchDownload
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..c7a7410439 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
sslinfo.o
EXTENSION = sslinfo
-DATA = sslinfo--1.2.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
+DATA = sslinfo--1.3.sql sslinfo--1.2--1.3.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
PGFILEDESC = "sslinfo - information about client SSL certificate"
ifdef USE_PGXS
diff --git a/contrib/sslinfo/sslinfo--1.2.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
similarity index 100%
rename from contrib/sslinfo/sslinfo--1.2.sql
rename to contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/sslinfo--1.3.sql b/contrib/sslinfo/sslinfo--1.3.sql
new file mode 100644
index 0000000000..62abec5b5c
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.3.sql
@@ -0,0 +1,56 @@
+/* contrib/sslinfo/sslinfo--1.3.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION sslinfo" to load this file. \quit
+
+CREATE FUNCTION ssl_client_serial() RETURNS numeric
+AS 'MODULE_PATHNAME', 'ssl_client_serial'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_is_used() RETURNS boolean
+AS 'MODULE_PATHNAME', 'ssl_is_used'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_version() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_version'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_cipher() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_cipher'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_cert_present() RETURNS boolean
+AS 'MODULE_PATHNAME', 'ssl_client_cert_present'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_dn_field(text) RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_dn_field'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_issuer_field(text) RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_issuer_field'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_dn() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_dn'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_issuer_dn() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_issuer_dn'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notbefore() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_get_notbefore'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notafter() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION
+ssl_extension_info(OUT name text,
+ OUT value text,
+ OUT critical boolean
+) RETURNS SETOF record
+AS 'MODULE_PATHNAME', 'ssl_extension_info'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..90195fa38f 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -482,3 +482,66 @@ ssl_extension_info(PG_FUNCTION_ARGS)
/* All done */
SRF_RETURN_DONE(funcctx);
}
+
+/*
+ * Returns current client certificate notBefore timestamp in
+ * the format of YYYY-MM-DDThh:mm:ss
+ */
+PG_FUNCTION_INFO_V1(ssl_client_get_notbefore);
+Datum
+ssl_client_get_notbefore(PG_FUNCTION_ARGS)
+{
+ X509 *cert = MyProcPort->peer;
+ char notbefore[NAMEDATALEN];
+ struct tm tm_notbefore;
+ ASN1_TIME *asn1_notbefore = NULL;
+
+ if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
+ PG_RETURN_NULL();
+
+ /* Get notBefore from client certificate */
+ asn1_notbefore = X509_getm_notBefore(cert);
+
+ /* convert to struct tm */
+ ASN1_TIME_to_tm(asn1_notbefore, &tm_notbefore);
+
+ /* convert to cstring */
+ memset(notbefore, 0, sizeof(notbefore));
+ snprintf(notbefore, sizeof(notbefore), "%04d-%02d-%02dT%02d:%02d:%02d",
+ tm_notbefore.tm_year+1900, tm_notbefore.tm_mon+1, tm_notbefore.tm_mday,
+ tm_notbefore.tm_hour, tm_notbefore.tm_min, tm_notbefore.tm_sec);
+
+ PG_RETURN_TEXT_P(cstring_to_text(notbefore));
+}
+
+/*
+ * Returns current client certificate notAfter timestamp in
+ * the format of YYYY-MM-DDThh:mm:ss
+ */
+PG_FUNCTION_INFO_V1(ssl_client_get_notafter);
+Datum
+ssl_client_get_notafter(PG_FUNCTION_ARGS)
+{
+ X509 *cert = MyProcPort->peer;
+ char notafter[NAMEDATALEN];
+ struct tm tm_notafter;
+ ASN1_TIME *asn1_notafter = NULL;
+
+ if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
+ PG_RETURN_NULL();
+
+ /* Get notBefore from client certificate */
+ asn1_notafter = X509_getm_notAfter(cert);
+
+ /* convert to struct tm */
+ ASN1_TIME_to_tm(asn1_notafter, &tm_notafter);
+
+ /* convert to cstring */
+ memset(notafter, 0, sizeof(notafter));
+ snprintf(notafter, sizeof(notafter), "%04d-%02d-%02dT%02d:%02d:%02d",
+ tm_notafter.tm_year+1900, tm_notafter.tm_mon+1, tm_notafter.tm_mday,
+ tm_notafter.tm_hour, tm_notafter.tm_min, tm_notafter.tm_sec);
+
+ PG_RETURN_TEXT_P(cstring_to_text(notafter));
+}
+
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 2a9c45a111..ec2ecd34fc 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -240,6 +240,36 @@ emailAddress
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notbefore() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notbefore</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not before</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notafter() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notafter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not after</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
Import Notes
Reply to msg id not found:
On 20 Aug 2022, at 01:00, Cary Huang <cary.huang@highgo.ca> wrote:
I noticed that sslinfo extension does not have functions to return current client certificate's notbefore and notafter timestamps which are also quite important attributes in a X509 certificate. The attached patch adds 2 functions to get notbefore and notafter timestamps from the currently connected client certificate.
Off the cuff that doesn't seem like a bad idea, but I wonder if we should add
them to pg_stat_ssl (or both) instead if we deem them valuable?
Re the patch, it would be nice to move the logic in ssl_client_get_notafter and
the _notbefore counterpart to a static function since they are copies of
eachother.
--
Daniel Gustafsson https://vmware.com/
Off the cuff that doesn't seem like a bad idea, but I wonder if we should add
them to pg_stat_ssl (or both) instead if we deem them valuable?
I think the same information should be available to pg_stat_ssl as well. pg_stat_ssl can show the client certificate information for all connecting clients, having it to show not_before and not_after timestamps of every client are important in my opinion. The attached patch "v2-0002-pg-stat-ssl-add-notbefore-and-notafter-timestamps.patch" adds this support
Re the patch, it would be nice to move the logic in ssl_client_get_notafter and
the _notbefore counterpart to a static function since they are copies of
eachother.
Yes agreed. I have made the adjustment attached as "v2-0001-sslinfo-add-notbefore-and-notafter-timestamps.patch"
would this feature be suitable to be added to commitfest? What do you think?
thank you
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
Attachments:
v2-0001-sslinfo-add-notbefore-and-notafter-timestamps.patchapplication/octet-stream; name=v2-0001-sslinfo-add-notbefore-and-notafter-timestamps.patchDownload
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..c7a7410439 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
sslinfo.o
EXTENSION = sslinfo
-DATA = sslinfo--1.2.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
+DATA = sslinfo--1.3.sql sslinfo--1.2--1.3.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
PGFILEDESC = "sslinfo - information about client SSL certificate"
ifdef USE_PGXS
diff --git a/contrib/sslinfo/sslinfo--1.2.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
similarity index 100%
rename from contrib/sslinfo/sslinfo--1.2.sql
rename to contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/sslinfo--1.3.sql b/contrib/sslinfo/sslinfo--1.3.sql
new file mode 100644
index 0000000000..62abec5b5c
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.3.sql
@@ -0,0 +1,56 @@
+/* contrib/sslinfo/sslinfo--1.3.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION sslinfo" to load this file. \quit
+
+CREATE FUNCTION ssl_client_serial() RETURNS numeric
+AS 'MODULE_PATHNAME', 'ssl_client_serial'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_is_used() RETURNS boolean
+AS 'MODULE_PATHNAME', 'ssl_is_used'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_version() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_version'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_cipher() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_cipher'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_cert_present() RETURNS boolean
+AS 'MODULE_PATHNAME', 'ssl_client_cert_present'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_dn_field(text) RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_dn_field'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_issuer_field(text) RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_issuer_field'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_dn() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_dn'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_issuer_dn() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_issuer_dn'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notbefore() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_get_notbefore'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notafter() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION
+ssl_extension_info(OUT name text,
+ OUT value text,
+ OUT critical boolean
+) RETURNS SETOF record
+AS 'MODULE_PATHNAME', 'ssl_extension_info'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..47bc549027 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -34,6 +34,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_text(ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -225,6 +226,36 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into text
+ *
+ * Convert ASN1_TIME structure to text representation in ISO 8601
+ * format in UTC time (YYYY-MM-DDThh:mm:ssZ)
+ *
+ * Parameter: time - OpenSSL ASN1_TIME structure.
+ *
+ * Returns Datum, which can be directly returned from a C language SQL
+ * function.
+ */
+static Datum
+ASN1_TIME_to_text(ASN1_TIME *time)
+{
+ struct tm tm_time;
+ char str_time[NAMEDATALEN];
+ text *result;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ memset(str_time, 0, sizeof(str_time));
+ snprintf(str_time, sizeof(str_time), "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ tm_time.tm_year+1900, tm_time.tm_mon+1, tm_time.tm_mday,
+ tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
+
+ result = cstring_to_text(str_time);
+ PG_RETURN_TEXT_P(result);
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +513,42 @@ ssl_extension_info(PG_FUNCTION_ARGS)
/* All done */
SRF_RETURN_DONE(funcctx);
}
+
+/*
+ * Returns current client certificate notBefore timestamp in
+ * ISO 8601 format of YYYY-MM-DDThh:mm:ssZ
+ */
+PG_FUNCTION_INFO_V1(ssl_client_get_notbefore);
+Datum
+ssl_client_get_notbefore(PG_FUNCTION_ARGS)
+{
+ X509 *cert = MyProcPort->peer;
+ ASN1_TIME *asn1_notbefore = NULL;
+
+ if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
+ PG_RETURN_NULL();
+
+ asn1_notbefore = X509_getm_notBefore(cert);
+
+ return ASN1_TIME_to_text(asn1_notbefore);
+}
+
+/*
+ * Returns current client certificate notAfter timestamp in
+ * ISO 8601 format of YYYY-MM-DDThh:mm:ssZ
+ */
+PG_FUNCTION_INFO_V1(ssl_client_get_notafter);
+Datum
+ssl_client_get_notafter(PG_FUNCTION_ARGS)
+{
+ X509 *cert = MyProcPort->peer;
+ ASN1_TIME *asn1_notafter = NULL;
+
+ if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
+ PG_RETURN_NULL();
+
+ asn1_notafter = X509_getm_notAfter(cert);
+
+ return ASN1_TIME_to_text(asn1_notafter);
+}
+
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..9c0b32a1b6 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -240,6 +240,36 @@ emailAddress
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notbefore() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notbefore</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not before</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notafter() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notafter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not after</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
v2-0002-pg-stat-ssl-add-notbefore-and-notafter-timestamps.patchapplication/octet-stream; name=v2-0002-pg-stat-ssl-add-notbefore-and-notafter-timestamps.patchDownload
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index c18fea8362..104420c2df 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -970,7 +970,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 05276ab95c..bbfe539c49 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -72,6 +72,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 char *ASN1_TIME_to_cstring(ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool SSL_initialized = false;
@@ -1408,6 +1409,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, char *ptr, size_t len)
+{
+ if (port->peer)
+ strlcpy(ptr, ASN1_TIME_to_cstring(X509_getm_notBefore(port->peer)), len);
+ else
+ ptr[0] = '\0';
+}
+
+void
+be_tls_get_peer_not_after(Port *port, char *ptr, size_t len)
+{
+ if (port->peer)
+ strlcpy(ptr, ASN1_TIME_to_cstring(X509_getm_notAfter(port->peer)), len);
+ else
+ ptr[0] = '\0';
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1553,6 +1572,27 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a cstring in format of YYYY-MM-DDThh:mm:ssZ.
+ */
+static char *
+ASN1_TIME_to_cstring(ASN1_TIME * time)
+{
+ struct tm tm_time;
+ char str_time[NAMEDATALEN];
+ char *result;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ memset(str_time, 0, sizeof(str_time));
+ snprintf(str_time, sizeof(str_time), "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ tm_time.tm_year+1900, tm_time.tm_mon+1, tm_time.tm_mday,
+ tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
+
+ result = pstrdup(str_time);
+ return result;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 38f91a495b..a9e6f21501 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -367,6 +367,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, NAMEDATALEN);
+ be_tls_get_peer_not_after(MyProcPort, lsslstatus.ssl_not_after, NAMEDATALEN);
}
else
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 2a4c8ef87f..ff10d63cbd 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -303,7 +303,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);
@@ -587,35 +587,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] = CStringGetTextDatum(beentry->st_sslstatus->ssl_not_before);
+ else
+ nulls[25] = true;
+
+ if (beentry->st_sslstatus->ssl_not_after[0])
+ values[26] = CStringGetTextDatum(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
{
@@ -645,6 +655,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 6996073989..7e71d80a48 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5413,9 +5413,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,text,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,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 => '3318',
descr => 'statistics: information about progress of backends running maintenance command',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 3b2ce9908f..3ec23b6feb 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -298,6 +298,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, char *ptr, size_t len);
+extern void be_tls_get_peer_not_after(Port *port, char *ptr, size_t len);
/*
* Get the server certificate hash for SCRAM channel binding type
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 77939a0aed..f9277454e4 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -61,6 +61,8 @@ typedef struct PgBackendSSLStatus
char ssl_client_serial[NAMEDATALEN];
char ssl_issuer_dn[NAMEDATALEN];
+ char ssl_not_before[NAMEDATALEN];
+ char ssl_not_after[NAMEDATALEN];
} PgBackendSSLStatus;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 7fd81e6a7d..231c01113a 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1760,7 +1760,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,
@@ -1878,7 +1878,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,
@@ -2078,7 +2078,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,
@@ -2111,8 +2111,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,
On 23 Jun 2023, at 22:10, Cary Huang <cary.huang@highgo.ca> wrote:
would this feature be suitable to be added to commitfest? What do you think?
Yes, please add it to the July commitfest and feel free to set me as Reviewer,
I intend to take a look at it.
--
Daniel Gustafsson
Yes, please add it to the July commitfest and feel free to set me as Reviewer,
I intend to take a look at it.
Thank you Daniel, I have added this patch to July commitfest under security category and added you as reviewer.
best regards
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
On 23 Jun 2023, at 22:10, Cary Huang <cary.huang@highgo.ca> wrote:
Off the cuff that doesn't seem like a bad idea, but I wonder if we should add
them to pg_stat_ssl (or both) instead if we deem them valuable?I think the same information should be available to pg_stat_ssl as well. pg_stat_ssl can show the client certificate information for all connecting clients, having it to show not_before and not_after timestamps of every client are important in my opinion. The attached patch "v2-0002-pg-stat-ssl-add-notbefore-and-notafter-timestamps.patch" adds this support
This needs to adjust the tests in src/test/ssl which now fails due to SELECT *
returning a row which doesn't match what the test was coded for.
Re the patch, it would be nice to move the logic in ssl_client_get_notafter and
the _notbefore counterpart to a static function since they are copies of
eachother.Yes agreed. I have made the adjustment attached as "v2-0001-sslinfo-add-notbefore-and-notafter-timestamps.patch"
The new patchset isn't updating contrib/sslinfo/meson with the 1.3 update so it
fails to build with Meson.
--
Daniel Gustafsson
This needs to adjust the tests in src/test/ssl which now fails due to SELECT *
returning a row which doesn't match what the test was coded for.
Thank you so much for pointing out. I have adjusted the extra ssl test to account for the extra columns returned. It should not fail now.
The new patchset isn't updating contrib/sslinfo/meson with the 1.3 update so it
fails to build with Meson.
Thanks again for pointing out, I have adjusted the meson build file to include the 1.3 update
Please see attached patches for the fixes.
Thank you so much!
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
Attachments:
v3-0001-sslinfo-add-notbefore-and-notafter-timestamps.patchapplication/octet-stream; name=v3-0001-sslinfo-add-notbefore-and-notafter-timestamps.patchDownload
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..c7a7410439 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
sslinfo.o
EXTENSION = sslinfo
-DATA = sslinfo--1.2.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
+DATA = sslinfo--1.3.sql sslinfo--1.2--1.3.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
PGFILEDESC = "sslinfo - information about client SSL certificate"
ifdef USE_PGXS
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 999456d3a4..296adbec8a 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -25,7 +25,8 @@ contrib_targets += sslinfo
install_data(
'sslinfo--1.0--1.1.sql',
'sslinfo--1.1--1.2.sql',
- 'sslinfo--1.2.sql',
+ 'sslinfo--1.2--1.3.sql',
+ 'sslinfo--1.3.sql',
'sslinfo.control',
kwargs: contrib_data_args,
)
diff --git a/contrib/sslinfo/sslinfo--1.2.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
similarity index 100%
rename from contrib/sslinfo/sslinfo--1.2.sql
rename to contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/sslinfo--1.3.sql b/contrib/sslinfo/sslinfo--1.3.sql
new file mode 100644
index 0000000000..62abec5b5c
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.3.sql
@@ -0,0 +1,56 @@
+/* contrib/sslinfo/sslinfo--1.3.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION sslinfo" to load this file. \quit
+
+CREATE FUNCTION ssl_client_serial() RETURNS numeric
+AS 'MODULE_PATHNAME', 'ssl_client_serial'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_is_used() RETURNS boolean
+AS 'MODULE_PATHNAME', 'ssl_is_used'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_version() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_version'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_cipher() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_cipher'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_cert_present() RETURNS boolean
+AS 'MODULE_PATHNAME', 'ssl_client_cert_present'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_dn_field(text) RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_dn_field'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_issuer_field(text) RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_issuer_field'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_dn() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_dn'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_issuer_dn() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_issuer_dn'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notbefore() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_get_notbefore'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notafter() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION
+ssl_extension_info(OUT name text,
+ OUT value text,
+ OUT critical boolean
+) RETURNS SETOF record
+AS 'MODULE_PATHNAME', 'ssl_extension_info'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..47bc549027 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -34,6 +34,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_text(ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -225,6 +226,36 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into text
+ *
+ * Convert ASN1_TIME structure to text representation in ISO 8601
+ * format in UTC time (YYYY-MM-DDThh:mm:ssZ)
+ *
+ * Parameter: time - OpenSSL ASN1_TIME structure.
+ *
+ * Returns Datum, which can be directly returned from a C language SQL
+ * function.
+ */
+static Datum
+ASN1_TIME_to_text(ASN1_TIME *time)
+{
+ struct tm tm_time;
+ char str_time[NAMEDATALEN];
+ text *result;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ memset(str_time, 0, sizeof(str_time));
+ snprintf(str_time, sizeof(str_time), "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ tm_time.tm_year+1900, tm_time.tm_mon+1, tm_time.tm_mday,
+ tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
+
+ result = cstring_to_text(str_time);
+ PG_RETURN_TEXT_P(result);
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +513,42 @@ ssl_extension_info(PG_FUNCTION_ARGS)
/* All done */
SRF_RETURN_DONE(funcctx);
}
+
+/*
+ * Returns current client certificate notBefore timestamp in
+ * ISO 8601 format of YYYY-MM-DDThh:mm:ssZ
+ */
+PG_FUNCTION_INFO_V1(ssl_client_get_notbefore);
+Datum
+ssl_client_get_notbefore(PG_FUNCTION_ARGS)
+{
+ X509 *cert = MyProcPort->peer;
+ ASN1_TIME *asn1_notbefore = NULL;
+
+ if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
+ PG_RETURN_NULL();
+
+ asn1_notbefore = X509_getm_notBefore(cert);
+
+ return ASN1_TIME_to_text(asn1_notbefore);
+}
+
+/*
+ * Returns current client certificate notAfter timestamp in
+ * ISO 8601 format of YYYY-MM-DDThh:mm:ssZ
+ */
+PG_FUNCTION_INFO_V1(ssl_client_get_notafter);
+Datum
+ssl_client_get_notafter(PG_FUNCTION_ARGS)
+{
+ X509 *cert = MyProcPort->peer;
+ ASN1_TIME *asn1_notafter = NULL;
+
+ if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
+ PG_RETURN_NULL();
+
+ asn1_notafter = X509_getm_notAfter(cert);
+
+ return ASN1_TIME_to_text(asn1_notafter);
+}
+
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..9c0b32a1b6 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -240,6 +240,36 @@ emailAddress
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notbefore() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notbefore</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not before</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notafter() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notafter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not after</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
v3-0002-pg-stat-ssl-add-notbefore-and-notafter-timestamps.patchapplication/octet-stream; name=v3-0002-pg-stat-ssl-add-notbefore-and-notafter-timestamps.patchDownload
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index c18fea8362..104420c2df 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -970,7 +970,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 05276ab95c..bbfe539c49 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -72,6 +72,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 char *ASN1_TIME_to_cstring(ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool SSL_initialized = false;
@@ -1408,6 +1409,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, char *ptr, size_t len)
+{
+ if (port->peer)
+ strlcpy(ptr, ASN1_TIME_to_cstring(X509_getm_notBefore(port->peer)), len);
+ else
+ ptr[0] = '\0';
+}
+
+void
+be_tls_get_peer_not_after(Port *port, char *ptr, size_t len)
+{
+ if (port->peer)
+ strlcpy(ptr, ASN1_TIME_to_cstring(X509_getm_notAfter(port->peer)), len);
+ else
+ ptr[0] = '\0';
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1553,6 +1572,27 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a cstring in format of YYYY-MM-DDThh:mm:ssZ.
+ */
+static char *
+ASN1_TIME_to_cstring(ASN1_TIME * time)
+{
+ struct tm tm_time;
+ char str_time[NAMEDATALEN];
+ char *result;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ memset(str_time, 0, sizeof(str_time));
+ snprintf(str_time, sizeof(str_time), "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ tm_time.tm_year+1900, tm_time.tm_mon+1, tm_time.tm_mday,
+ tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
+
+ result = pstrdup(str_time);
+ return result;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 38f91a495b..a9e6f21501 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -367,6 +367,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, NAMEDATALEN);
+ be_tls_get_peer_not_after(MyProcPort, lsslstatus.ssl_not_after, NAMEDATALEN);
}
else
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 2a4c8ef87f..ff10d63cbd 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -303,7 +303,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);
@@ -587,35 +587,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] = CStringGetTextDatum(beentry->st_sslstatus->ssl_not_before);
+ else
+ nulls[25] = true;
+
+ if (beentry->st_sslstatus->ssl_not_after[0])
+ values[26] = CStringGetTextDatum(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
{
@@ -645,6 +655,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 6996073989..7e71d80a48 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5413,9 +5413,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,text,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,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 => '3318',
descr => 'statistics: information about progress of backends running maintenance command',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 3b2ce9908f..3ec23b6feb 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -298,6 +298,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, char *ptr, size_t len);
+extern void be_tls_get_peer_not_after(Port *port, char *ptr, size_t len);
/*
* Get the server certificate hash for SCRAM channel binding type
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 77939a0aed..f9277454e4 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -61,6 +61,8 @@ typedef struct PgBackendSSLStatus
char ssl_client_serial[NAMEDATALEN];
char ssl_issuer_dn[NAMEDATALEN];
+ char ssl_not_before[NAMEDATALEN];
+ char ssl_not_after[NAMEDATALEN];
} PgBackendSSLStatus;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 7fd81e6a7d..231c01113a 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1760,7 +1760,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,
@@ -1878,7 +1878,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,
@@ -2078,7 +2078,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,
@@ -2111,8 +2111,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 76442de063..e9db6fd060 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -543,8 +543,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.
@@ -745,8 +745,8 @@ command_like(
'-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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E\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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E,2021-03-03T22:12:07Z,2048-07-19T22:12:07Z\r?$}mx,
'pg_stat_ssl with client certificate');
# client key with wrong permissions
On 30 Jun 2023, at 20:12, Cary Huang <cary.huang@highgo.ca> wrote:
This needs to adjust the tests in src/test/ssl which now fails due to SELECT *
returning a row which doesn't match what the test was coded for.Thank you so much for pointing out. I have adjusted the extra ssl test to account for the extra columns returned. It should not fail now.
Thanks for the new version! It doesn't fail the ssl tests, but the Kerberos
test now fails. You can see the test reports from the CFBot here:
http://cfbot.cputube.org/cary-huang.html
This runs on submitted patches, you can also run the same CI checks in your own
Github clone using the supplied CI files in the postgres repo.
There are also some trivial whitespace issues shown with "git diff --check",
these can of course easily be addressed by a committer in a final-version patch
but when sending a new version you might as well fix those.
The new patchset isn't updating contrib/sslinfo/meson with the 1.3 update so it
fails to build with Meson.Thanks again for pointing out, I have adjusted the meson build file to include the 1.3 update
+ asn1_notbefore = X509_getm_notBefore(cert);
X509_getm_notBefore() and X509_getm_notAfter() are only available in OpenSSL
1.1.1 and onwards, but postgres support 1.0.2 (as of today with 8e278b6576).
X509_get_notAfter() is available in 1.0.2 but deprecated in 1.1.1 and turned
into an alias for X509_getm_notAfter() (same with _notBefore of course), and
since we set 1.0.2 as the API compatibility we should be able to use that
without warnings instead.
+ <function>ssl_client_get_notbefore() returns text</function>
+ <function>ssl_client_get_notafter() returns text</function>
These functions should IMO return timestamp data types to save the user from
having to convert them. Same with the additions to pg_stat_get_activity.
You should add tests for the new functions in src/test/ssl/t/003_sslinfo.pl.
--
Daniel Gustafsson
Thanks for the new version! It doesn't fail the ssl tests, but the Kerberos
test now fails. You can see the test reports from the CFBot here:
Yes, kerberos tests failed due to the addition of notbefore and notafter values. The values array within "pg_stat_get_activity" function related to "pg_stat_gssapi" were not set correctly. It is now fixed
This runs on submitted patches, you can also run the same CI checks in your own
Github clone using the supplied CI files in the postgres repo.
Thank you for pointing this out. I followed the CI instruction as suggested and am able to run the same CI checks to reproduce the test failures.
There are also some trivial whitespace issues shown with "git diff --check",
these can of course easily be addressed by a committer in a final-version patch
but when sending a new version you might as well fix those.
Yes, the white spaces issues should be addressed in the attached patches.
X509_getm_notBefore() and X509_getm_notAfter() are only available in OpenSSL
1.1.1 and onwards, but postgres support 1.0.2 (as of today with 8e278b6576).
X509_get_notAfter() is available in 1.0.2 but deprecated in 1.1.1 and turned
into an alias for X509_getm_notAfter() (same with _notBefore of course), and
since we set 1.0.2 as the API compatibility we should be able to use that
without warnings instead.
Thank you so much for catching this openssl function compatibility issue. I have changed the function calls to:
- X509_get_notBefore()
- X509_get_notAfter()
which are compatible in OpenSSL v1.0.2 and also v1.1.1 where they will get translated to X509_getm_notBefore() and X509_getm_notAfter() respectively
These functions should IMO return timestamp data types to save the user from
having to convert them. Same with the additions to pg_stat_get_activity.
Yes, agreed, the attached patches have the output changed to timestamp datatype instead of text.
You should add tests for the new functions in src/test/ssl/t/003_sslinfo.pl.
Yes, agreed, I added 2 additional tests in src/test/ssl/t/003_sslinfo.pl to compare the notbefore and notafter outputs from sslinfo extension and pg_stat_ssl outputs. Both should be tested equal.
Also added related documentation about the new not before and not after timestamps in pg_stat_ssl.
thank you
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
Attachments:
v4-0001-sslinfo-add-notbefore-and-notafter-timestamps.patchapplication/octet-stream; name=v4-0001-sslinfo-add-notbefore-and-notafter-timestamps.patchDownload
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..c7a7410439 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
sslinfo.o
EXTENSION = sslinfo
-DATA = sslinfo--1.2.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
+DATA = sslinfo--1.3.sql sslinfo--1.2--1.3.sql sslinfo--1.1--1.2.sql sslinfo--1.0--1.1.sql
PGFILEDESC = "sslinfo - information about client SSL certificate"
ifdef USE_PGXS
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 999456d3a4..296adbec8a 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -25,7 +25,8 @@ contrib_targets += sslinfo
install_data(
'sslinfo--1.0--1.1.sql',
'sslinfo--1.1--1.2.sql',
- 'sslinfo--1.2.sql',
+ 'sslinfo--1.2--1.3.sql',
+ 'sslinfo--1.3.sql',
'sslinfo.control',
kwargs: contrib_data_args,
)
diff --git a/contrib/sslinfo/sslinfo--1.2.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
similarity index 100%
rename from contrib/sslinfo/sslinfo--1.2.sql
rename to contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/sslinfo--1.3.sql b/contrib/sslinfo/sslinfo--1.3.sql
new file mode 100644
index 0000000000..0033be1616
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.3.sql
@@ -0,0 +1,56 @@
+/* contrib/sslinfo/sslinfo--1.3.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION sslinfo" to load this file. \quit
+
+CREATE FUNCTION ssl_client_serial() RETURNS numeric
+AS 'MODULE_PATHNAME', 'ssl_client_serial'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_is_used() RETURNS boolean
+AS 'MODULE_PATHNAME', 'ssl_is_used'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_version() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_version'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_cipher() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_cipher'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_cert_present() RETURNS boolean
+AS 'MODULE_PATHNAME', 'ssl_client_cert_present'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_dn_field(text) RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_dn_field'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_issuer_field(text) RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_issuer_field'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_dn() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_client_dn'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_issuer_dn() RETURNS text
+AS 'MODULE_PATHNAME', 'ssl_issuer_dn'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notbefore() RETURNS timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notbefore'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notafter() RETURNS timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION
+ssl_extension_info(OUT name text,
+ OUT value text,
+ OUT critical boolean
+) RETURNS SETOF record
+AS 'MODULE_PATHNAME', 'ssl_extension_info'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..dd4157ff21 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#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 +35,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_timestamp(ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -225,6 +227,39 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into timestamp
+ *
+ * Parameter: time - OpenSSL ASN1_TIME structure.
+ *
+ * Returns Datum, which can be directly returned from a C language SQL
+ * function.
+ */
+static Datum
+ASN1_TIME_to_timestamp(ASN1_TIME *time)
+{
+ struct tm tm_time;
+ struct pg_tm pgtm_time;
+ Timestamp ts;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ pgtm_time.tm_sec = tm_time.tm_sec;
+ pgtm_time.tm_min = tm_time.tm_min;
+ pgtm_time.tm_hour = tm_time.tm_hour;
+ pgtm_time.tm_mday = tm_time.tm_mday;
+ pgtm_time.tm_mon = tm_time.tm_mon + 1;
+ pgtm_time.tm_year = tm_time.tm_year + 1900;
+
+ if (tm2timestamp(&pgtm_time, 0, NULL, &ts))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("failed to convert tm to timestamp")));
+
+ PG_RETURN_TIMESTAMP(ts);
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +517,35 @@ ssl_extension_info(PG_FUNCTION_ARGS)
/* All done */
SRF_RETURN_DONE(funcctx);
}
+
+/*
+ * Returns current client certificate notBefore timestamp in
+ * timestamp 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_timestamp(X509_get_notBefore(cert));
+}
+
+/*
+ * Returns current client certificate notAfter timestamp in
+ * timestamp 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_timestamp(X509_get_notAfter(cert));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..06f5728096 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -240,6 +240,36 @@ emailAddress
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notbefore() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notbefore</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not before</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notafter() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notafter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not after</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
v4-0002-pg-stat-ssl-add-notbefore-and-notafter-timestamps.patchapplication/octet-stream; name=v4-0002-pg-stat-ssl-add-notbefore-and-notafter-timestamps.patchDownload
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 506aeaa879..161c2154f7 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2257,6 +2257,26 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
This field is truncated like <structfield>client_dn</structfield>.
</para></entry>
</row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>not_befoer</structfield> <type>text</type>
+ </para>
+ <para>
+ Not before UTC 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 UTC timestamp of the client certificate, or NULL if no client
+ certificate was supplied
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index c18fea8362..104420c2df 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -970,7 +970,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 658b09988d..3170a585da 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -36,6 +36,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 +73,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 Timestamp ASN1_TIME_to_timestamp(ASN1_TIME * time);
static SSL_CTX *SSL_context = NULL;
static bool SSL_initialized = false;
@@ -1406,6 +1408,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, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notBefore(port->peer));
+ else
+ *ptr = 0;
+}
+
+void
+be_tls_get_peer_not_after(Port *port, Timestamp * ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notAfter(port->peer));
+ else
+ *ptr = 0;
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1549,6 +1569,33 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a cstring in format of YYYY-MM-DDThh:mm:ssZ.
+ */
+static Timestamp
+ASN1_TIME_to_timestamp(ASN1_TIME * time)
+{
+ struct tm tm_time;
+ struct pg_tm pgtm_time;
+ Timestamp ts;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ pgtm_time.tm_sec = tm_time.tm_sec;
+ pgtm_time.tm_min = tm_time.tm_min;
+ pgtm_time.tm_hour = tm_time.tm_hour;
+ pgtm_time.tm_mday = tm_time.tm_mday;
+ pgtm_time.tm_mon = tm_time.tm_mon + 1;
+ pgtm_time.tm_year = tm_time.tm_year + 1900;
+
+ if (tm2timestamp(&pgtm_time, 0, NULL, &ts))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("failed to convert tm to timestamp")));
+
+ return ts;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 38f91a495b..02dc9d7931 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -367,6 +367,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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 2a4c8ef87f..9071981f98 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -303,7 +303,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);
@@ -395,7 +395,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
pfree(clipped_activity);
/* leader_pid */
- nulls[29] = true;
+ nulls[31] = true;
proc = BackendPidGetProc(beentry->st_procpid);
@@ -432,8 +432,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)
{
@@ -441,8 +441,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;
}
}
}
@@ -587,35 +587,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] = TimestampGetDatum(beentry->st_sslstatus->ssl_not_before);
+ else
+ nulls[25] = true;
+
+ if (beentry->st_sslstatus->ssl_not_after != 0)
+ values[26] = TimestampGetDatum(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
{
@@ -645,6 +655,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 6996073989..878c997e87 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5413,9 +5413,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,timestamp,timestamp,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 => '3318',
descr => 'statistics: information about progress of backends running maintenance command',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index a0b74c8095..c9d7ae659a 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -298,6 +298,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, Timestamp * ptr);
+extern void be_tls_get_peer_not_after(Port *port, Timestamp * ptr);
/*
* Get the server certificate hash for SCRAM channel binding type
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 77939a0aed..1e4fedb661 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -61,6 +61,8 @@ typedef struct PgBackendSSLStatus
char ssl_client_serial[NAMEDATALEN];
char ssl_issuer_dn[NAMEDATALEN];
+ Timestamp ssl_not_before;
+ Timestamp ssl_not_after;
} PgBackendSSLStatus;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 7fd81e6a7d..231c01113a 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1760,7 +1760,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,
@@ -1878,7 +1878,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,
@@ -2078,7 +2078,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,
@@ -2111,8 +2111,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 76442de063..6d93499d50 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -543,8 +543,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.
@@ -745,8 +745,8 @@ command_like(
'-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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E\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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E,\Q2021-03-03 22:12:07\E,\Q2048-07-19 22:12:07\E\r?$}mx,
'pg_stat_ssl with client certificate');
# client key with wrong permissions
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 5306aad802..b9a220431c 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -165,6 +165,18 @@ $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 FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
+ connstr => $common_connstr);
+is($result, 't', "ssl_client_get_notbefore() for not_before timestamp");
+
+$result = $node->safe_psql(
+ "certdb",
+ "SELECT ssl_client_get_notafter() = not_after FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
+ connstr => $common_connstr);
+is($result, 't', "ssl_client_get_notafter() for not_after timestamp");
+
$result = $node->safe_psql(
"certdb",
"SELECT value, critical FROM ssl_extension_info() WHERE name = 'basicConstraints';",
I had another look at this today and I think this patch is in pretty good
shape, below are a few comments on this revision:
- 'sslinfo--1.2.sql',
+ 'sslinfo--1.2--1.3.sql',
+ 'sslinfo--1.3.sql',
The way we typically ship extensions in contrib/ is to not create a new base
version .sql file for smaller changes like adding a few functions. For this
patch we should keep --1.2.sql and instead supply a 1.2--1.3.sql with the new
functions.
+ <structfield>not_befoer</structfield> <type>text</type>
s/not_befoer/not_before/
+ errmsg("failed to convert tm to timestamp")));
I think this error is too obscure for the user to act on, what we use elsewhere
is "timestamp out of range" and I think thats more helpful. I do wonder if
there is ever a legitimate case when this can fail while still having a
authenticated client connection?
+ ^\d+,t,TLSv[\d.]+,[\w-]+,\d+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E,\Q2021-03-03 22:12:07\E,\Q2048-07-19 22:12:07\E\r?$}mx,
This test output won't actually work for testing against, it works now because
the dates match the current set of certificates, but the certificates can be
regenerated with `cd src/test/ssl && make -f sslfiles.mk` and that will change
the not_before/not_after dates. In order to have stable test data we need to
set fixed end/start dates and reissue all the client certs.
+ "SELECT ssl_client_get_notbefore() = not_before FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
+ connstr => $common_connstr);
+is($result, 't', "ssl_client_get_notbefore() for not_before timestamp");
While this works, it will fail to catch if we have the same bug in both sslinfo
and the backend. With stable test data we can add the actual date in the mix
and verify that both timestamps are equal and that they match the expected
date.
I have addressed the issues above in a new v5 patchset which includes a new
patch for setting stable validity on the test certificates (the notBefore time
was arbitrarily chosen to match the date of opening up the tree for v17 - we
just need a date in the past). Your two patches are rolled into a single one
with a commit message added to get started on that part as well.
--
Daniel Gustafsson
Attachments:
v5-0001-Set-fixed-dates-for-test-certificates-validity.patchapplication/octet-stream; name=v5-0001-Set-fixed-dates-for-test-certificates-validity.patch; x-unix-mode=0644Download
From b1c76ef7fab37693f65c67bbb7be707e8c0e0285 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Thu, 13 Jul 2023 17:44:22 +0200
Subject: [PATCH v5 1/2] Set fixed dates for test certificates validity
Rather than specifying a validity of 10 000 days into the future
for test certificate generation, this hardcodes the notBefore and
notAfter attributes to set values. This will allow writing tests
which will not depend on when the certificates were generated. An
upcoming patch for adding notBefore and notAfter to pg_stat_ssl
and sslinfo requires this.
Discussion: https://postgr.es/m/182b8565486.10af1a86f158715.2387262617218380588@highgo.ca
---
src/test/ssl/conf/cas.config | 5 +-
src/test/ssl/ssl/both-cas-1.crt | 70 ++++++++++---------
src/test/ssl/ssl/both-cas-2.crt | 70 ++++++++++---------
src/test/ssl/ssl/client+client_ca.crt | 65 +++++++++--------
src/test/ssl/ssl/client-crldir/9bb9e3c3.r0 | 20 +++---
src/test/ssl/ssl/client-dn.crt | 32 ++++-----
src/test/ssl/ssl/client-long.crt | 34 ++++-----
src/test/ssl/ssl/client-revoked-utf8.crt | 30 ++++----
src/test/ssl/ssl/client-revoked.crt | 30 ++++----
src/test/ssl/ssl/client.crl | 20 +++---
src/test/ssl/ssl/client.crt | 30 ++++----
src/test/ssl/ssl/client_ca.crt | 35 +++++-----
src/test/ssl/ssl/client_ext.crt | 33 +++++----
.../ssl/ssl/root+client-crldir/9bb9e3c3.r0 | 20 +++---
src/test/ssl/ssl/root+client.crl | 20 +++---
src/test/ssl/ssl/root+client_ca.crt | 35 +++++-----
.../ssl/ssl/root+server-crldir/a836cc2d.r0 | 18 ++---
src/test/ssl/ssl/root+server.crl | 18 ++---
src/test/ssl/ssl/root+server_ca.crt | 35 +++++-----
src/test/ssl/ssl/server-cn-and-alt-names.crt | 36 +++++-----
.../ssl/ssl/server-cn-and-ip-alt-names.crt | 35 +++++-----
src/test/ssl/ssl/server-cn-only+server_ca.crt | 67 +++++++++---------
src/test/ssl/ssl/server-cn-only.crt | 32 ++++-----
src/test/ssl/ssl/server-crldir/a836cc2d.r0 | 18 ++---
src/test/ssl/ssl/server-ip-alt-names.crt | 33 ++++-----
.../ssl/ssl/server-ip-cn-and-alt-names.crt | 34 ++++-----
.../ssl/server-ip-cn-and-dns-alt-names.crt | 35 +++++-----
src/test/ssl/ssl/server-ip-cn-only.crt | 30 ++++----
src/test/ssl/ssl/server-ip-in-dnsname.crt | 32 +++++----
.../ssl/ssl/server-multiple-alt-names.crt | 36 +++++-----
src/test/ssl/ssl/server-no-names.crt | 30 ++++----
src/test/ssl/ssl/server-revoked.crt | 32 ++++-----
src/test/ssl/ssl/server-single-alt-name.crt | 33 ++++-----
src/test/ssl/ssl/server.crl | 18 ++---
src/test/ssl/ssl/server_ca.crt | 35 +++++-----
35 files changed, 600 insertions(+), 556 deletions(-)
diff --git a/src/test/ssl/conf/cas.config b/src/test/ssl/conf/cas.config
index 2c4851033a..43bcf739bb 100644
--- a/src/test/ssl/conf/cas.config
+++ b/src/test/ssl/conf/cas.config
@@ -38,7 +38,10 @@ crl = ./ssl/server.crl
dir = ./ssl/
database = ./ssl/client_ca-certindex
default_md = sha256
-default_days= 10000
+# Startdate and enddate are required for testing notBefore/notAfter with
+# stable timestamps.
+default_startdate = 20230629010101Z
+default_enddate = 20500101010101Z
default_crl_days= 10000
certificate = ./ssl/client_ca.crt
private_key = ./ssl/client_ca.key
diff --git a/src/test/ssl/ssl/both-cas-1.crt b/src/test/ssl/ssl/both-cas-1.crt
index 4f4bc707d6..1584b4ba0e 100644
--- a/src/test/ssl/ssl/both-cas-1.crt
+++ b/src/test/ssl/ssl/both-cas-1.crt
@@ -18,40 +18,46 @@ OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/both-cas-2.crt b/src/test/ssl/ssl/both-cas-2.crt
index 01d0c4d6a4..674d8e6a7e 100644
--- a/src/test/ssl/ssl/both-cas-2.crt
+++ b/src/test/ssl/ssl/both-cas-2.crt
@@ -18,40 +18,46 @@ OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client+client_ca.crt b/src/test/ssl/ssl/client+client_ca.crt
index 7fafa14de1..fe7719e14b 100644
--- a/src/test/ssl/ssl/client+client_ca.crt
+++ b/src/test/ssl/ssl/client+client_ca.crt
@@ -1,37 +1,40 @@
-----BEGIN CERTIFICATE-----
-MIIC0zCCAbsCCCAhAwMUEgcAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC1TCCAb0CCCAjBxMWNSQAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAWMRQwEgYDVQQD
-DAtzc2x0ZXN0dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALSL
-oC6h8sBABL8kWRjFQJHZNcwmuRRWjzhBYR4gDKcBThCBIuEr5PZEkkXnJniXKHct
-bCzaBarUwG+bWGg6BiFWX3PP5MZvLG7ExP9yTrDjdwjKozkJCNWSow0hdYLaxkpm
-rYI6rDJ5T1CZBRLD4RYOjU39WVIxYkHlhJYtH0Cdv5PuzCOEtLdKQySSVq6heJen
-koLvK7AaF1x8uDiwM+o9t69pORWbOh/6aCCPeYmvhPIRvEqyZjGvPJ2kXau4R1vN
-NmepRIZ0VjQ/rQxo7dGWk38cfgsTeFI4G26DiYn08pFR47swUdfiMyx3MaGQiz9X
-I2nUqjM+W84iUxrR82MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEACSZo32raJHcB
-rYHeomzynmzgMVBHSA4XsXZVQw4+zBUER+/ZdQbtw6F/qdeWRvTl8TJjwoydta7u
-4gUkgAnQhYm2f8XEBe/+MUegH+y54Yk6rtmkdLxJLGKZ0IUfYkn20sg/NZrltbog
-A8glWRGVD8cEOaxUaNSQ4Xqmqsqjd6Kh8snVfIIcWgKgnTNgyapM5ePBpS2IREhN
-u9fjikQQf6F/dycsm22OP7aWsp1XPs3nqnoq9ZnhQrITMwsGcjbU7+v8La2GbiJV
-8yAy136NSXUujIG/8eqhICWZPqj+KbdVZupOsUeVoeuSwLXJjm4GWY0xH92emqCI
-ac+HriJv5w==
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMBYxFDASBgNV
+BAMMC3NzbHRlc3R1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+tIugLqHywEAEvyRZGMVAkdk1zCa5FFaPOEFhHiAMpwFOEIEi4Svk9kSSRecmeJco
+dy1sLNoFqtTAb5tYaDoGIVZfc8/kxm8sbsTE/3JOsON3CMqjOQkI1ZKjDSF1gtrG
+SmatgjqsMnlPUJkFEsPhFg6NTf1ZUjFiQeWEli0fQJ2/k+7MI4S0t0pDJJJWrqF4
+l6eSgu8rsBoXXHy4OLAz6j23r2k5FZs6H/poII95ia+E8hG8SrJmMa88naRdq7hH
+W802Z6lEhnRWND+tDGjt0ZaTfxx+CxN4UjgbboOJifTykVHjuzBR1+IzLHcxoZCL
+P1cjadSqMz5bziJTGtHzYwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAQnfs7UO2g
+iilUgCQAfa9Vb0ZSivD7ryjnLsdwYRLIlb0YceME9qtSv2UYBfS9KpwG7+jONMQB
+kvbe611/TaF0T7EC1GIWuTMs8jknJ2bgPbS8D8jiFWTci+SDDog4EVoakSLoirW6
+yB4398upjtanAdnjoNpE4REXPDHzDm2Dico2RCObJh1VAEK+q6gLJxQtGvdPyG3L
+Fhjs7ky1lsxIvHlts8c1e4vhnVpxdS3I5r6N38qFXEJnc1tv/e+TH50mdrZlzRHF
+TPgnZzWCGTHmT5YT3yoAldWG4uWzMsB+2eY/crRefM9byc0omjCxDTrk9nA6JWsf
+0c6pBc6aKzdi
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0 b/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0
index f75eb1c0bc..202f9f44d0 100644
--- a/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0
+++ b/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0
@@ -1,12 +1,12 @@
-----BEGIN X509 CRL-----
-MIIBwDCBqTANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMjA3
-MTgyMjI4MTVaFw00OTEyMDMyMjI4MTVaMDYwGQIIICEDAxQSBwEXDTIyMDcxODIy
-MjgxNVowGQIIICIHGBUoFQAXDTIyMDcxODIyMjgxNVowDQYJKoZIhvcNAQELBQAD
-ggEBAFDH3m9AHpDjkEFjO6svnLJ2bTliGeKZaJW8/RAN4mWvWDhXDQfzqGcFHN2a
-SIL57Xc4PdwTiXuU4QEP4RvWW90LYKdcrcT8uh0AN3i7ShMwcV7I7owzF5+CBuT7
-Ev0MU4QIz0PjXoybXP6b3wHhZbEjYTLYdnYdqjrsAchUpyDQn6fiC0C7FgjCi4HL
-rNm2kMchFpzd6K9e41kxWVp7xCPXgqUK8OrxlW56ObkX8UpBIZzyU6RisJKOZJAn
-/+lwT43yTtU739atdXdSMvGHT9Y7LsrSDz9zgp2/iMTmfctnPcp81J/6jQZEP8kx
-OyPyZz4xy/EShWy+KUklfOoKRo8=
+MIIBwjCBqzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNjAZAgggIwcTFjUkAhcNMjMwNzEz
+MTQzNTI0WjAZAgggIwcTFjUkBRcNMjMwNzEzMTQzNTI0WjANBgkqhkiG9w0BAQsF
+AAOCAQEAl2jqLuwUgUTtzIKdLyAqIGf+zG0jfJXD9KFIsPeR+zfYWyNVzlWav68e
+zcLLhr9NWzHCXo0F5yiWVIO9pe2OF980Ez/24fTd6NPk3qG9AzLeLQ0jPhEgLaDw
+KFSTuaTbEuAUBGHMTjdoe6aOGsypUOXxse/G5enyx93yCC7boFkrYscfnQT2kFZT
+60Bhfr/4qkFdGJbp9ZIsTP8us4sktEDFn24Tq5f8sW7JyqIU83LRhjkIc8NALGCE
+DE7FgaGVUyuH8jYkVw4XLMwYo9gAy95pBxrDFq/r0Zm4E1rIEr8x7Ji7smUcubrb
+/MXu7OCXst4uzoRxFQctnP19AYIKZQ==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/client-dn.crt b/src/test/ssl/ssl/client-dn.crt
index 0db14e5977..3f5c80580c 100644
--- a/src/test/ssl/ssl/client-dn.crt
+++ b/src/test/ssl/ssl/client-dn.crt
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDDTCCAfUCCCAhBikTA0IAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDDzCCAfcCCCAjBxMWNSQBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjEwNjI5MjAwMzQyWhcNNDgxMTE0MjAwMzQyWjBQMQ0wCwYDVQQK
-DARQR0RHMRQwEgYDVQQLDAtFbmdpbmVlcmluZzEQMA4GA1UECwwHVGVzdGluZzEX
-MBUGA1UEAwwOc3NsdGVzdHVzZXItZG4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDES64qtkofPjeG4VbUVKfzABLC0CurvxqLTEpokq/St9WAWDrzc8PJ
-YireEZp4ec5rHVyQVvHqzzaZFAMvbRUQgMdGKG4Vgkn8l96KxHa4Q6yxYoQOts10
-AuvU9LuGKT0lxndMggHDmREUOAkFYKp7IeypseUGkJ6sWs+DlTwK1hST+EUAU/5f
-q/pAngJ+oar20m8WNxaAhJUKtBBecdRdqYy/h3Ab43iPhj+N9IFXiSV9EWhteBae
-L/TEE+s7/4L74xwvJe2EiVETo3lMy2aVJ4/4pOMq7U+Gr/0wxk0jqRrOahAE6pOI
-cQFBFsOkyUaC4dzqtjeSrsw5igQbJC19AgMBAAEwDQYJKoZIhvcNAQELBQADggEB
-AECbQQ9rBzCexNI3VKDVA+CZa0ib48XbcJwXmva3spvjjCB5cGPToyF1B+4mVg1H
-1uM/XRAoQmNRtB+xKEAceMSxJA02tBlwMOclXlO0oGLYyc+S61K+UEPSk6Kka4aC
-NpeLSqN5ahC9z8C5uMJl36pFf13aU05uRkXKcI4gkn02I4jRc/a8gF7URdhdf920
-KmYSUh1V0B3pPAB6ArqJ60iHOqkCYIIIbi2EpVP53IKkoB9tr4ud8oMoN6ggIXU1
-2oHvnaKJ7RZaQNefS3WweyHxr4cCVtEour/ELph48OuW6Y5jqPT+5Ln3Qz0e6KW9
-o3thBx0aKSYlmt9gH254M9M=
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMFAxDTALBgNV
+BAoMBFBHREcxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRAwDgYDVQQLDAdUZXN0aW5n
+MRcwFQYDVQQDDA5zc2x0ZXN0dXNlci1kbjCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMRLriq2Sh8+N4bhVtRUp/MAEsLQK6u/GotMSmiSr9K31YBYOvNz
+w8liKt4Rmnh5zmsdXJBW8erPNpkUAy9tFRCAx0YobhWCSfyX3orEdrhDrLFihA62
+zXQC69T0u4YpPSXGd0yCAcOZERQ4CQVgqnsh7Kmx5QaQnqxaz4OVPArWFJP4RQBT
+/l+r+kCeAn6hqvbSbxY3FoCElQq0EF5x1F2pjL+HcBvjeI+GP430gVeJJX0RaG14
+Fp4v9MQT6zv/gvvjHC8l7YSJUROjeUzLZpUnj/ik4yrtT4av/TDGTSOpGs5qEATq
+k4hxAUEWw6TJRoLh3Oq2N5KuzDmKBBskLX0CAwEAATANBgkqhkiG9w0BAQsFAAOC
+AQEAYi8MtTEYoqqxjoy/QOYuuWIryNwvpHh9ty8q+r8gWPuySMaIb+qfWh7qK1OY
+ng9HUXdXn+kpZIy6GMVtVSprPn5J3gLCZMsXqHxh5XtHf8DkSwmaQrVSFmu0Wkri
+txnNl4OHwMIGbX0o6oN7rNdlgYxLyMtPzO+KfygjO4HX8Hm5Jz0DM2K3airnFkCc
+IwYdMmaEMykRRl2W5wpSgHjYrReL3qopdWj97sKTY4H3ZuBR7i2V9ni6/mJFUD2u
+8tLeUTB1vOhRk6JhtRagNIQHg7tsUX6Fx3QkdosGjSCWPePzv4UC4GYvEjbOvsxv
+hIPtSVIjtS8eN6co3XJP+dTd4w==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-long.crt b/src/test/ssl/ssl/client-long.crt
index a1db55b5c3..2fec398e17 100644
--- a/src/test/ssl/ssl/client-long.crt
+++ b/src/test/ssl/ssl/client-long.crt
@@ -1,20 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDWjCCAkICCCAiBRIUREYAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDXDCCAkQCCCAjBxMWNSQEMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjIwNTEyMjE0NDQ3WhcNNDkwOTI3MjE0NDQ3WjCBnDEsMCoGA1UE
-CgwjUG9zdGdyZVNRTCBHbG9iYWwgRGV2ZWxvcG1lbnQgR3JvdXAxITAfBgNVBAsM
-GFNvbWUgT3JnYW5pemF0aW9uYWwgVW5pdDFJMEcGA1UEAwxAc3NsLTEyMzQ1Njc4
-OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2
-Nzg5MDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgxmeHiVRuBTwlG
-Q1oM2M1ckQCI/o4hYcO9BYdxDYHiA7jy1WVenyj8BtUi5Aj9VDhpfiuewDarGQ5a
-TggD1pMjkw0MorBKBr9+1u1xGH/8Q3lkgU+OQXrPglo4IrVcqaoZFQ0nuMaVbieX
-0dDyTfsTaVQYYtqAtzhI/UGSIOhk2+lB9fP68jw9cLH0QYvR+qQ0IPG13I5zmSYP
-Mj0VYwMn9TF9/2sBOSRVgTVAcrYgOQLk3s/fGe66tmVBIWYcq65ygqD1+weu+Pax
-jPnwsefkdnf6JdYRG1F1Co7g52poPEYieAHfQOJ69sG0LYx0lBODC69qvSJ4WdCQ
-0zKw288CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEArr5r1UxgUzPykmu5ZdL6y8TA
-ZbSQ1yBY0nhsRwRkDd66iPK9U6T6K2+pL8Vc6ioov9WOtHQ6ohP3gSavd40cHRmF
-auwIsZ4Wk0mjftpOuPFp1hyo8d/QYrbEm3qNe5qln5S9h8ipoYvFtf5zlK2KHJFz
-9ehZMZ1zGAERNCVM8UUQKyUuZB5GyrZlbslf6P/9Bsc54YUWxP2pr5r/RJ6DeXfI
-zAFfXT8AFVlClARA949gpX0LVrXryDN60CUJ88QJmYCQ3AtIgzYYeqcdYHTd8eS2
-9P5whDdU5NvROP+LjETeReJF4Bfyc2gM7zxZD2BDSf5exvnNqiy42/lR1b4szw==
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMIGcMSwwKgYD
+VQQKDCNQb3N0Z3JlU1FMIEdsb2JhbCBEZXZlbG9wbWVudCBHcm91cDEhMB8GA1UE
+CwwYU29tZSBPcmdhbml6YXRpb25hbCBVbml0MUkwRwYDVQQDDEBzc2wtMTIzNDU2
+Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0
+NTY3ODkwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2DGZ4eJVG4FP
+CUZDWgzYzVyRAIj+jiFhw70Fh3ENgeIDuPLVZV6fKPwG1SLkCP1UOGl+K57ANqsZ
+DlpOCAPWkyOTDQyisEoGv37W7XEYf/xDeWSBT45Bes+CWjgitVypqhkVDSe4xpVu
+J5fR0PJN+xNpVBhi2oC3OEj9QZIg6GTb6UH18/ryPD1wsfRBi9H6pDQg8bXcjnOZ
+Jg8yPRVjAyf1MX3/awE5JFWBNUBytiA5AuTez98Z7rq2ZUEhZhyrrnKCoPX7B674
+9rGM+fCx5+R2d/ol1hEbUXUKjuDnamg8RiJ4Ad9A4nr2wbQtjHSUE4MLr2q9InhZ
+0JDTMrDbzwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCUIOBu5ea3vSVpiqCGMphv
+V26dDpEl1OMpvPIM5Ss1sp9ogOdBg7ahkDE51J0QaB3yN6mci3sN6yi77U3zXXUv
+qI0hdR3nwjTLJSpW2p6ONW43PKPhKr42UdBH5iRVlNY7rto2x3xC0iuzvPAJjIJJ
+OJMZYl/A43O8XZW68m9Z5kH3Vi/l0wtjElfnjqI0DAuQEL/TQTzK9qTIhdAqMAKG
+deTGSqpz+ID2CfuN+TBV2NAseilZ4JC0xZxaJpoqmK3yTtgKBhJ3vQN//fc1TdPy
+9+zvnSRIJZJque58ZKnqbMq3c3RRSo0eOZn7FZopcIRsn5hzDeIVTJcBJ68jcxrL
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-revoked-utf8.crt b/src/test/ssl/ssl/client-revoked-utf8.crt
index de471d1e60..4189c75de8 100644
--- a/src/test/ssl/ssl/client-revoked-utf8.crt
+++ b/src/test/ssl/ssl/client-revoked-utf8.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC2DCCAcACCCAiBxgVKBUAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC2jCCAcICCCAjBxMWNSQFMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjIwNzE4MjIyODE1WhcNNDkxMjAzMjIyODE1WjAbMRkwFwYDVQQD
-DBDOn860z4XPg8+Dzq3Osc+CMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAvBiL1mVjTrzZ6sbrvfu746dzh+EEyuJNkCwPeJTtpva2wqqRUMYw05cV5kzi
-YQ3UikMP5Yz0FXTeWoahSpJAWeR5XsFx3wOQvRzwi1KWm2CHr/rb7KbPvoZQdXuV
-8UeKrQ6PrEvjoarHAUZuWyUC6EnEAGuiKl5yuax5mkTcK5F8pig2/SS/UonX5ar5
-58rOUEaIdyZmXtrO86cm5S5Oz3G2naQB3PPPOhtkoGBHikRHiqBPVRpX3w9TIpBL
-BZbT4MIZ+fCjZ9wXj4aiDUzPglu6/Tfx9sNcxc6Ilz/XHfPuBVyyjgrny2SrW0W4
-KlhU09y+m5gKL358z8tj599DowIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAE47ns
-wfceztieaRQtoF+gPcCuImOJqaB7jTE6cQ+aoW/q+sUlOh7AD0IZqhS4o0A4O+ny
-MD7kHkpYP+ctHNomsSQRkFTDZ2ZJGcRgxbwMOSvsKcgNOTMGqpXQiP0x0m7QMBGl
-EHeu5MqG/IK/ZlH9aOTvSnHegB6ztct/7wXMeFCflsWLp6wvnv9YpddaaXf95Oms
-9kwbVYkI1wxaBsAO8VGbJw1YtdErgd65qKTJa45xndtm61i1Jeig5asSNQPwjfZ5
-aNHZ9GsSwsc31Q/6iiezbPwgdAi3ih//uB2hznkMhObnqzR3n8Sw9zgL7DdFr2y9
-2R7kJuGq6DvlWFYS
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMBsxGTAXBgNV
+BAMMEM6fzrTPhc+Dz4POrc6xz4IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC8GIvWZWNOvNnqxuu9+7vjp3OH4QTK4k2QLA94lO2m9rbCqpFQxjDTlxXm
+TOJhDdSKQw/ljPQVdN5ahqFKkkBZ5HlewXHfA5C9HPCLUpabYIev+tvsps++hlB1
+e5XxR4qtDo+sS+OhqscBRm5bJQLoScQAa6IqXnK5rHmaRNwrkXymKDb9JL9Sidfl
+qvnnys5QRoh3JmZe2s7zpyblLk7PcbadpAHc8886G2SgYEeKREeKoE9VGlffD1Mi
+kEsFltPgwhn58KNn3BePhqINTM+CW7r9N/H2w1zFzoiXP9cd8+4FXLKOCufLZKtb
+RbgqWFTT3L6bmAovfnzPy2Pn30OjAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAASZ
+M/4tx9qm7G9TEKHHg/Da7GOrGWnYwluWcO/jnIN4jCPyxwj6EmxZGEBKqFUhj3kY
+hwL+249Y2YABOLqu9x/YJz1KtZUgkwTGh6yfT5xOSOCXij7ukpge1gXtodYtnBgP
+FmJOdFygrXxWex3vr+F2Fnh93Isxd/nFof/Rwmi4JTJr6JjalyGuvNDGZc/N16/u
+uR3AE0zGLfM093GbJe9E9j44DGMbNlwHvZ2NXojX34kNoRttonPHmXGKWSCyufUc
+uG+STq5T/DFnr06Ugj2TPCMyEgDEA4unzP5uxAijXVRSkyOrAtZrFtzbab/wjTLt
+0AGeljtaei/bMAh11Cs=
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-revoked.crt b/src/test/ssl/ssl/client-revoked.crt
index 51ebe924a6..2cc0c933cd 100644
--- a/src/test/ssl/ssl/client-revoked.crt
+++ b/src/test/ssl/ssl/client-revoked.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC0zCCAbsCCCAhAwMUEgcBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC1TCCAb0CCCAjBxMWNSQCMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAWMRQwEgYDVQQD
-DAtzc2x0ZXN0dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKAX
-JmNmfqmvpVAeWEmJxi7feku2sZKA7yMyyZMCboBqsNVO9gOpQFE8gD1Z7bJm4aDK
-QxByuspYPFOBwty9YW4UqRa4kyEyd08x+PsHQx9SmWJTNpNIH6yq5LCcme37QMrg
-b8wUZRWwXsaKUfVUI6oALjSgcibMJXTntCsD9J5m/07U/ZZALe1460rreTFHsxVZ
-708Wm5u7UHIgxvvEKhNG/JR9zd1Tl1mVgnlz0a8G6Dt22gJnLnuFdtDdACwET/kG
-TRJQWuyavpe+1TY53kZNO442hOzwhlZVnz4IKaWaLNQMtbG9iYStEvaWa8p0E/3J
-N6oRuELiqXJp/wW3v/MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAcVhPcu55HcSf
-Mci38T/fOBaiDUvzWwG/XlQRzFxcS+ZY/vYMbgor6PliGlCFBF4Mca2qtTs7zXRz
-8aLNVX53p98Cnnn97mW4aYNbNdM87R76IqJdj40brEolu1JNOyFJRYzoaebABf9r
-R64FTt3YVM9qjJrHG/apYwKwgAMxVzZ/M+3ujahP/8mOYD/Utj+lYHnXJmuHAYE6
-EnTxTSb2J+IsK8KuPoGjUPNZRW8zIUE0luMpJahvtmFVW91Vue7dW0AOmHpjmGUB
-J9Vwxe7KJRW5/4dz6kMD2pKY3D9sBgXeku/QDVz/hdyB5YT0WChFiZn20DZyhOtu
-moHgw8OJzg==
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMBYxFDASBgNV
+BAMMC3NzbHRlc3R1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+oBcmY2Z+qa+lUB5YSYnGLt96S7axkoDvIzLJkwJugGqw1U72A6lAUTyAPVntsmbh
+oMpDEHK6ylg8U4HC3L1hbhSpFriTITJ3TzH4+wdDH1KZYlM2k0gfrKrksJyZ7ftA
+yuBvzBRlFbBexopR9VQjqgAuNKByJswldOe0KwP0nmb/TtT9lkAt7XjrSut5MUez
+FVnvTxabm7tQciDG+8QqE0b8lH3N3VOXWZWCeXPRrwboO3baAmcue4V20N0ALARP
++QZNElBa7Jq+l77VNjneRk07jjaE7PCGVlWfPggppZos1Ay1sb2JhK0S9pZrynQT
+/ck3qhG4QuKpcmn/Bbe/8wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtVsoTdoLZ
+2PMVSDIEc3VRhjNS5+EuYcW+7h0se/7IpBauHoZhn+JD8YVtE04yz2YkglrnChmJ
+iL8xc+f1PbQatxpU7HnSswn3JevC+jZWnGvAxqR2oR3cAioF7sK1vnYLnd2OPqcy
+P9T+tzi90fiVOVOlrm00hjJBNcDIhofjY9td3wogA1SO8vXQteZ1gXNt0nzmfuNZ
+vZvspk+A/vN8tbR6BTagUxPRxajiT0xoIJFD6Qx2ZPglgffJKDwQQ3kvYr7dLMgO
++TDcLL8GK2MAxglgOqvUlRwfwl0ZXu3ZsGjim8pF+dPJB1dUCm9KbG2sIscPNLUe
+9p2w5FZaNk7p
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client.crl b/src/test/ssl/ssl/client.crl
index f75eb1c0bc..202f9f44d0 100644
--- a/src/test/ssl/ssl/client.crl
+++ b/src/test/ssl/ssl/client.crl
@@ -1,12 +1,12 @@
-----BEGIN X509 CRL-----
-MIIBwDCBqTANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMjA3
-MTgyMjI4MTVaFw00OTEyMDMyMjI4MTVaMDYwGQIIICEDAxQSBwEXDTIyMDcxODIy
-MjgxNVowGQIIICIHGBUoFQAXDTIyMDcxODIyMjgxNVowDQYJKoZIhvcNAQELBQAD
-ggEBAFDH3m9AHpDjkEFjO6svnLJ2bTliGeKZaJW8/RAN4mWvWDhXDQfzqGcFHN2a
-SIL57Xc4PdwTiXuU4QEP4RvWW90LYKdcrcT8uh0AN3i7ShMwcV7I7owzF5+CBuT7
-Ev0MU4QIz0PjXoybXP6b3wHhZbEjYTLYdnYdqjrsAchUpyDQn6fiC0C7FgjCi4HL
-rNm2kMchFpzd6K9e41kxWVp7xCPXgqUK8OrxlW56ObkX8UpBIZzyU6RisJKOZJAn
-/+lwT43yTtU739atdXdSMvGHT9Y7LsrSDz9zgp2/iMTmfctnPcp81J/6jQZEP8kx
-OyPyZz4xy/EShWy+KUklfOoKRo8=
+MIIBwjCBqzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNjAZAgggIwcTFjUkAhcNMjMwNzEz
+MTQzNTI0WjAZAgggIwcTFjUkBRcNMjMwNzEzMTQzNTI0WjANBgkqhkiG9w0BAQsF
+AAOCAQEAl2jqLuwUgUTtzIKdLyAqIGf+zG0jfJXD9KFIsPeR+zfYWyNVzlWav68e
+zcLLhr9NWzHCXo0F5yiWVIO9pe2OF980Ez/24fTd6NPk3qG9AzLeLQ0jPhEgLaDw
+KFSTuaTbEuAUBGHMTjdoe6aOGsypUOXxse/G5enyx93yCC7boFkrYscfnQT2kFZT
+60Bhfr/4qkFdGJbp9ZIsTP8us4sktEDFn24Tq5f8sW7JyqIU83LRhjkIc8NALGCE
+DE7FgaGVUyuH8jYkVw4XLMwYo9gAy95pBxrDFq/r0Zm4E1rIEr8x7Ji7smUcubrb
+/MXu7OCXst4uzoRxFQctnP19AYIKZQ==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/client.crt b/src/test/ssl/ssl/client.crt
index 1f6ae05fe4..eaf8830192 100644
--- a/src/test/ssl/ssl/client.crt
+++ b/src/test/ssl/ssl/client.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC0zCCAbsCCCAhAwMUEgcAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC1TCCAb0CCCAjBxMWNSQAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAWMRQwEgYDVQQD
-DAtzc2x0ZXN0dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALSL
-oC6h8sBABL8kWRjFQJHZNcwmuRRWjzhBYR4gDKcBThCBIuEr5PZEkkXnJniXKHct
-bCzaBarUwG+bWGg6BiFWX3PP5MZvLG7ExP9yTrDjdwjKozkJCNWSow0hdYLaxkpm
-rYI6rDJ5T1CZBRLD4RYOjU39WVIxYkHlhJYtH0Cdv5PuzCOEtLdKQySSVq6heJen
-koLvK7AaF1x8uDiwM+o9t69pORWbOh/6aCCPeYmvhPIRvEqyZjGvPJ2kXau4R1vN
-NmepRIZ0VjQ/rQxo7dGWk38cfgsTeFI4G26DiYn08pFR47swUdfiMyx3MaGQiz9X
-I2nUqjM+W84iUxrR82MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEACSZo32raJHcB
-rYHeomzynmzgMVBHSA4XsXZVQw4+zBUER+/ZdQbtw6F/qdeWRvTl8TJjwoydta7u
-4gUkgAnQhYm2f8XEBe/+MUegH+y54Yk6rtmkdLxJLGKZ0IUfYkn20sg/NZrltbog
-A8glWRGVD8cEOaxUaNSQ4Xqmqsqjd6Kh8snVfIIcWgKgnTNgyapM5ePBpS2IREhN
-u9fjikQQf6F/dycsm22OP7aWsp1XPs3nqnoq9ZnhQrITMwsGcjbU7+v8La2GbiJV
-8yAy136NSXUujIG/8eqhICWZPqj+KbdVZupOsUeVoeuSwLXJjm4GWY0xH92emqCI
-ac+HriJv5w==
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMBYxFDASBgNV
+BAMMC3NzbHRlc3R1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+tIugLqHywEAEvyRZGMVAkdk1zCa5FFaPOEFhHiAMpwFOEIEi4Svk9kSSRecmeJco
+dy1sLNoFqtTAb5tYaDoGIVZfc8/kxm8sbsTE/3JOsON3CMqjOQkI1ZKjDSF1gtrG
+SmatgjqsMnlPUJkFEsPhFg6NTf1ZUjFiQeWEli0fQJ2/k+7MI4S0t0pDJJJWrqF4
+l6eSgu8rsBoXXHy4OLAz6j23r2k5FZs6H/poII95ia+E8hG8SrJmMa88naRdq7hH
+W802Z6lEhnRWND+tDGjt0ZaTfxx+CxN4UjgbboOJifTykVHjuzBR1+IzLHcxoZCL
+P1cjadSqMz5bziJTGtHzYwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAQnfs7UO2g
+iilUgCQAfa9Vb0ZSivD7ryjnLsdwYRLIlb0YceME9qtSv2UYBfS9KpwG7+jONMQB
+kvbe611/TaF0T7EC1GIWuTMs8jknJ2bgPbS8D8jiFWTci+SDDog4EVoakSLoirW6
+yB4398upjtanAdnjoNpE4REXPDHzDm2Dico2RCObJh1VAEK+q6gLJxQtGvdPyG3L
+Fhjs7ky1lsxIvHlts8c1e4vhnVpxdS3I5r6N38qFXEJnc1tv/e+TH50mdrZlzRHF
+TPgnZzWCGTHmT5YT3yoAldWG4uWzMsB+2eY/crRefM9byc0omjCxDTrk9nA6JWsf
+0c6pBc6aKzdi
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client_ca.crt b/src/test/ssl/ssl/client_ca.crt
index ef48749f76..31867bd0f4 100644
--- a/src/test/ssl/ssl/client_ca.crt
+++ b/src/test/ssl/ssl/client_ca.crt
@@ -1,19 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client_ext.crt b/src/test/ssl/ssl/client_ext.crt
index 9874ce49b9..5204391e46 100644
--- a/src/test/ssl/ssl/client_ext.crt
+++ b/src/test/ssl/ssl/client_ext.crt
@@ -1,21 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDezCCAmOgAwIBAgIIICEREAQyQQAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDQTCCAimgAwIBAgIIICMHExY1JAMwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IGNs
-aWVudCBjZXJ0czAeFw0yMTExMTAwMzMyNDFaFw00OTAzMjgwMzMyNDFaMBYxFDAS
-BgNVBAMMC3NzbHRlc3R1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEArCHikkEQLFITbn3ZfO8X2RW3fELeaImgy8W4Pkkc4LxdHCWjdCML/vtE/ZVu
-Op74qrQQWT0HKXFVUiZLbjAgV2PONS6VFHhc3sTFxuTaBnVdY+K98hoFnXskINt/
-wgwUhRcRZuKPcZvEHiqF6e3g3lQa99l1nVKPGPLOCvVhSgoV0Gwgxok0t7s25BCV
-ZmpMAwSTxpeviLF0e2MsttuyClQ4nuD92EHZX3BuG0WNPLxiwikV96uMffpMRGsx
-uiAHzD5ykYM7/b3eU0bjfi0J0qcfTSeytqFuRCNEukJpmtUmyYGqsFJ7HN7ejCY7
-ObAlBn8h+4bgwBRaeZDZLTMaYQIDAQABo4GgMIGdMAwGA1UdEwEB/wQCMAAwEwYD
+aWVudCBjZXJ0czAgFw0yMzA2MjkwMTAxMDFaGA8yMDUwMDEwMTAxMDEwMVowFjEU
+MBIGA1UEAwwLc3NsdGVzdHVzZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCsIeKSQRAsUhNufdl87xfZFbd8Qt5oiaDLxbg+SRzgvF0cJaN0Iwv++0T9
+lW46nviqtBBZPQcpcVVSJktuMCBXY841LpUUeFzexMXG5NoGdV1j4r3yGgWdeyQg
+23/CDBSFFxFm4o9xm8QeKoXp7eDeVBr32XWdUo8Y8s4K9WFKChXQbCDGiTS3uzbk
+EJVmakwDBJPGl6+IsXR7Yyy227IKVDie4P3YQdlfcG4bRY08vGLCKRX3q4x9+kxE
+azG6IAfMPnKRgzv9vd5TRuN+LQnSpx9NJ7K2oW5EI0S6Qmma1SbJgaqwUnsc3t6M
+Jjs5sCUGfyH7huDAFFp5kNktMxphAgMBAAGjZTBjMAwGA1UdEwEB/wQCMAAwEwYD
VR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFPPv1n7k1Vd9BBC4eoGWPZwVz2Lx
-MFkGA1UdIwRSMFChRKRCMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBmb3IgUG9z
-dGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlggggIQMDFBIHATANBgkq
-hkiG9w0BAQsFAAOCAQEAtqIeTmUhtHyCt5k2yx88F0dKshYq4Z+LQI+agyZ1fRE6
-Ux5p+SBGbzvc+NcUvc7yGG6w2G/nTVnGwSHN9NtQa2T2XbHJysJ/dwCfmRsachKz
-4kCp0zAHEDrEmZua0sy5BLwwVCk5WNBR0lZ35WmIEuRA+5G/2lCywtrb9W4YnbAM
-nH7BtZE8qPbK4OicB40I2NXz6KhG3755oKN03VC1IaX9JFQxf37ac7jVK5bsjfaF
-0xCAeuDN6wDiVHZj6q1GhhmNLzaF5zmU2e/cI1nTI5tfGKnygavlZIz2VvAlcypt
-YZdMDy69VbTWUa57UPCspghgvm5M2/Hjmz50CXGMvw==
+MB8GA1UdIwQYMBaAFJ+k69LJmd6wA7AwNCKBYRVLva02MA0GCSqGSIb3DQEBCwUA
+A4IBAQBsDUu6W6jXfgOkBGhZpwTtpThQ3fizEmBLXiy479Sa27YzdXCrLkql+XDv
+Z0nh8t7gvSw5ZCl9eZ13yg9etAfGCkNtkI37EVh4rMMqP3NkjBT2qwdG+pfwcF/c
++vrSK3H47lVIE5AShJJAwlU0Thf1bfyjzTnoGxEj2+YBMMhAykp9XbAgtM14hCQV
+07niaMv4kmmHDoUU72UH7GYnfnsCkUKhbisw7qOojd4MPX/kvU77+S3UURHJKKHy
+Rag+GP03NeF+d1z3niVBOIXE6hzlfaxB0w0SW7fXgQFYRBujTUYdcSZ5ZuT9kHyH
+9zHx+isaomV7U7yIQ9mGT/fDugki
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0 b/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0
index f75eb1c0bc..202f9f44d0 100644
--- a/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0
+++ b/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0
@@ -1,12 +1,12 @@
-----BEGIN X509 CRL-----
-MIIBwDCBqTANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMjA3
-MTgyMjI4MTVaFw00OTEyMDMyMjI4MTVaMDYwGQIIICEDAxQSBwEXDTIyMDcxODIy
-MjgxNVowGQIIICIHGBUoFQAXDTIyMDcxODIyMjgxNVowDQYJKoZIhvcNAQELBQAD
-ggEBAFDH3m9AHpDjkEFjO6svnLJ2bTliGeKZaJW8/RAN4mWvWDhXDQfzqGcFHN2a
-SIL57Xc4PdwTiXuU4QEP4RvWW90LYKdcrcT8uh0AN3i7ShMwcV7I7owzF5+CBuT7
-Ev0MU4QIz0PjXoybXP6b3wHhZbEjYTLYdnYdqjrsAchUpyDQn6fiC0C7FgjCi4HL
-rNm2kMchFpzd6K9e41kxWVp7xCPXgqUK8OrxlW56ObkX8UpBIZzyU6RisJKOZJAn
-/+lwT43yTtU739atdXdSMvGHT9Y7LsrSDz9zgp2/iMTmfctnPcp81J/6jQZEP8kx
-OyPyZz4xy/EShWy+KUklfOoKRo8=
+MIIBwjCBqzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNjAZAgggIwcTFjUkAhcNMjMwNzEz
+MTQzNTI0WjAZAgggIwcTFjUkBRcNMjMwNzEzMTQzNTI0WjANBgkqhkiG9w0BAQsF
+AAOCAQEAl2jqLuwUgUTtzIKdLyAqIGf+zG0jfJXD9KFIsPeR+zfYWyNVzlWav68e
+zcLLhr9NWzHCXo0F5yiWVIO9pe2OF980Ez/24fTd6NPk3qG9AzLeLQ0jPhEgLaDw
+KFSTuaTbEuAUBGHMTjdoe6aOGsypUOXxse/G5enyx93yCC7boFkrYscfnQT2kFZT
+60Bhfr/4qkFdGJbp9ZIsTP8us4sktEDFn24Tq5f8sW7JyqIU83LRhjkIc8NALGCE
+DE7FgaGVUyuH8jYkVw4XLMwYo9gAy95pBxrDFq/r0Zm4E1rIEr8x7Ji7smUcubrb
+/MXu7OCXst4uzoRxFQctnP19AYIKZQ==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+client.crl b/src/test/ssl/ssl/root+client.crl
index 459f48da43..2e0616905c 100644
--- a/src/test/ssl/ssl/root+client.crl
+++ b/src/test/ssl/ssl/root+client.crl
@@ -10,14 +10,14 @@ SBNr2rpYp7Coc3GeCoWPcClgSrABD3Z5GY1YAdLGiXVKaH3CmdJTznhEPagE4z5R
+GrJP3XxJ1OC
-----END X509 CRL-----
-----BEGIN X509 CRL-----
-MIIBwDCBqTANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMjA3
-MTgyMjI4MTVaFw00OTEyMDMyMjI4MTVaMDYwGQIIICEDAxQSBwEXDTIyMDcxODIy
-MjgxNVowGQIIICIHGBUoFQAXDTIyMDcxODIyMjgxNVowDQYJKoZIhvcNAQELBQAD
-ggEBAFDH3m9AHpDjkEFjO6svnLJ2bTliGeKZaJW8/RAN4mWvWDhXDQfzqGcFHN2a
-SIL57Xc4PdwTiXuU4QEP4RvWW90LYKdcrcT8uh0AN3i7ShMwcV7I7owzF5+CBuT7
-Ev0MU4QIz0PjXoybXP6b3wHhZbEjYTLYdnYdqjrsAchUpyDQn6fiC0C7FgjCi4HL
-rNm2kMchFpzd6K9e41kxWVp7xCPXgqUK8OrxlW56ObkX8UpBIZzyU6RisJKOZJAn
-/+lwT43yTtU739atdXdSMvGHT9Y7LsrSDz9zgp2/iMTmfctnPcp81J/6jQZEP8kx
-OyPyZz4xy/EShWy+KUklfOoKRo8=
+MIIBwjCBqzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNjAZAgggIwcTFjUkAhcNMjMwNzEz
+MTQzNTI0WjAZAgggIwcTFjUkBRcNMjMwNzEzMTQzNTI0WjANBgkqhkiG9w0BAQsF
+AAOCAQEAl2jqLuwUgUTtzIKdLyAqIGf+zG0jfJXD9KFIsPeR+zfYWyNVzlWav68e
+zcLLhr9NWzHCXo0F5yiWVIO9pe2OF980Ez/24fTd6NPk3qG9AzLeLQ0jPhEgLaDw
+KFSTuaTbEuAUBGHMTjdoe6aOGsypUOXxse/G5enyx93yCC7boFkrYscfnQT2kFZT
+60Bhfr/4qkFdGJbp9ZIsTP8us4sktEDFn24Tq5f8sW7JyqIU83LRhjkIc8NALGCE
+DE7FgaGVUyuH8jYkVw4XLMwYo9gAy95pBxrDFq/r0Zm4E1rIEr8x7Ji7smUcubrb
+/MXu7OCXst4uzoRxFQctnP19AYIKZQ==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+client_ca.crt b/src/test/ssl/ssl/root+client_ca.crt
index 7819c54828..ff8281fba0 100644
--- a/src/test/ssl/ssl/root+client_ca.crt
+++ b/src/test/ssl/ssl/root+client_ca.crt
@@ -18,21 +18,24 @@ OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0 b/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0
index 331a83cb62..7ed68e0220 100644
--- a/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0
+++ b/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0
@@ -1,11 +1,11 @@
-----BEGIN X509 CRL-----
-MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
-MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
-MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
-+10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
-4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
-ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
-imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
-B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+MIIBpzCBkDANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowGzAZAgggIwcTFjUjCxcNMjMwNzEz
+MTQzNTI0WjANBgkqhkiG9w0BAQsFAAOCAQEADIkF8oS84O2PJw/C9BAzgrkd+EsO
+QL6mXUGBgXwmujfpv0Z8YK91k4+xV9hQRMjWe/DkU01+gmFhYoDvAzweuNQzx8lZ
+bYKu0dGTEpTd+OG1LbxYmt4f5xh096R5iLo7c7e2kMHvfNG7VwvKQrPeMqh7AcKy
+Fukt8C0Xc7Tfv2l2toEQUAl5UDUKEAovN6iB0qycpvi0nboyiDo8mV0p1jlAn846
+EeXjwm8tyGXzTFq16ypPwnlBM9d5Ml/p5WTN69nDux18G+iSCr+UDzLDYvLF11p3
+lEqpSo5lQg9zYuOgMCvu3g5BtwJgORPSiW/yZ5BXUfWvPi0XRPrknxMByA==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+server.crl b/src/test/ssl/ssl/root+server.crl
index 8b0c716d63..93ffa5986e 100644
--- a/src/test/ssl/ssl/root+server.crl
+++ b/src/test/ssl/ssl/root+server.crl
@@ -10,13 +10,13 @@ SBNr2rpYp7Coc3GeCoWPcClgSrABD3Z5GY1YAdLGiXVKaH3CmdJTznhEPagE4z5R
+GrJP3XxJ1OC
-----END X509 CRL-----
-----BEGIN X509 CRL-----
-MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
-MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
-MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
-+10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
-4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
-ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
-imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
-B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+MIIBpzCBkDANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowGzAZAgggIwcTFjUjCxcNMjMwNzEz
+MTQzNTI0WjANBgkqhkiG9w0BAQsFAAOCAQEADIkF8oS84O2PJw/C9BAzgrkd+EsO
+QL6mXUGBgXwmujfpv0Z8YK91k4+xV9hQRMjWe/DkU01+gmFhYoDvAzweuNQzx8lZ
+bYKu0dGTEpTd+OG1LbxYmt4f5xh096R5iLo7c7e2kMHvfNG7VwvKQrPeMqh7AcKy
+Fukt8C0Xc7Tfv2l2toEQUAl5UDUKEAovN6iB0qycpvi0nboyiDo8mV0p1jlAn846
+EeXjwm8tyGXzTFq16ypPwnlBM9d5Ml/p5WTN69nDux18G+iSCr+UDzLDYvLF11p3
+lEqpSo5lQg9zYuOgMCvu3g5BtwJgORPSiW/yZ5BXUfWvPi0XRPrknxMByA==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+server_ca.crt b/src/test/ssl/ssl/root+server_ca.crt
index 5074f4fa9b..a094886e0f 100644
--- a/src/test/ssl/ssl/root+server_ca.crt
+++ b/src/test/ssl/ssl/root+server_ca.crt
@@ -18,21 +18,24 @@ OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-and-alt-names.crt b/src/test/ssl/ssl/server-cn-and-alt-names.crt
index 12d1ec363e..982c02a514 100644
--- a/src/test/ssl/ssl/server-cn-and-alt-names.crt
+++ b/src/test/ssl/ssl/server-cn-and-alt-names.crt
@@ -1,20 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIDVTCCAj2gAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDmTCCAoGgAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTAzMDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMEYxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5h
-bWUucGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAwVES+mD1iY1UBGWNLsuBxGkyOGTI1X/sXcCUZ7aLOGkXHYatiUTcIrSNNAS5
-yCvbq/A/C1NuDw59nrU2TitcLBx5AIhz74EV+xv/u/GuX0gvJzDWh/6EeMzDIcJL
-Iq7iEgO8ff5fuAzuwuNguZkX51JjBiXc2rtfgPI3CMU1lqCbb2vW9ZN4Pm7wRqvd
-d/F/mySiFmLFsB4HLhCGZN89vO4cbslN4+YrGKEcHeXGWRaxv6gSXbpEgUYpefzz
-+QB7AepU5aWntm3X+E1we5AHLSKckwUdBuT5uYgmZcYA/kCC4/9RS02jTlu4Vfrd
-SemHwuo2UQ5ODJxzAhWrEl3F4QIDAQABo0swSTBHBgNVHREEQDA+gh1kbnMxLmFs
-dC1uYW1lLnBnLXNzbHRlc3QudGVzdIIdZG5zMi5hbHQtbmFtZS5wZy1zc2x0ZXN0
-LnRlc3QwDQYJKoZIhvcNAQELBQADggEBAG3dFQ/DqjFbjzIOni079R3I94lAZqbc
-cRUumDPSzihKwvCCnU5quqnYkOFISqBZsYmxR5fiHx4wT+jmWvLSltkaeS6gcGC1
-zuO8GFzL+PATUX63js8IfE3WYJE/bjmDVVzJOBArrbsExofdE2F2kkkLkjhk0ylg
-/TrAKtyqpsob0b4ZjMloR5JFHQXGHN/922x6Do1vduHMXlGckmR0sX6Mg/fiChVh
-vixUJje4W9ohft8G7lj3GnzI1gHEMp2PYKM+wqOug/gXEQuMIFlhjp2Mc6bAvFsD
-grgdAgcYUvgKukF9efJHq2V5XjqBWrmGAOQkiH1y+9gxhiHUiw+vojY=
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjNaGA8yMDUwMTEyODE0MzUyM1owRjEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMSQwIgYDVQQDDBtjb21tb24t
+bmFtZS5wZy1zc2x0ZXN0LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDBURL6YPWJjVQEZY0uy4HEaTI4ZMjVf+xdwJRntos4aRcdhq2JRNwitI00
+BLnIK9ur8D8LU24PDn2etTZOK1wsHHkAiHPvgRX7G/+78a5fSC8nMNaH/oR4zMMh
+wksiruISA7x9/l+4DO7C42C5mRfnUmMGJdzau1+A8jcIxTWWoJtva9b1k3g+bvBG
+q9138X+bJKIWYsWwHgcuEIZk3z287hxuyU3j5isYoRwd5cZZFrG/qBJdukSBRil5
+/PP5AHsB6lTlpae2bdf4TXB7kActIpyTBR0G5Pm5iCZlxgD+QILj/1FLTaNOW7hV
++t1J6YfC6jZRDk4MnHMCFasSXcXhAgMBAAGjgYwwgYkwRwYDVR0RBEAwPoIdZG5z
+MS5hbHQtbmFtZS5wZy1zc2x0ZXN0LnRlc3SCHWRuczIuYWx0LW5hbWUucGctc3Ns
+dGVzdC50ZXN0MB0GA1UdDgQWBBQnWI8n7O4aU6PooSwyIepyrEpsajAfBgNVHSME
+GDAWgBTyjzpmQFBkSCLXLoL/Vp7Cs+50CjANBgkqhkiG9w0BAQsFAAOCAQEAQk/M
+emDTPYUx/JrSdTyvVDeBaUMUjWQ78LO1j/2RqtBXh/tSnTvalOeuwBPqmz9+7HYR
+H2gYQNq4W1Y6SgTdbpEivEXPvp1XyQXtLMpwDGO4rKq3QOCOPX2zZLDPrRqGSev3
+jN7oV8C3yVUyhhSxu+BZo4lZ55soiehCjHNKR5xfcbR/AtshLullVNNqoGQQyalS
+9TNUKp7FqF52tIELvFMINoSf5aaLU1g7snxnVRbTFyne/oqeqFjW932M/vaFgAH7
+H8mfoJeAiG5GqVBKtf3kcakfBl1wjFCzpguvDd9Xi2AP1y3cPEotwFiKhCYMmGiA
+EnzrdmAeNGKb2w3wlA==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt b/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt
index 4e58c85ccb..fea2703aaf 100644
--- a/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt
+++ b/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt
@@ -1,20 +1,21 @@
-----BEGIN CERTIFICATE-----
-MIIDLzCCAhegAwIBAgIIICERKRE1UQAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDcTCCAlmgAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTExMjkxOTM1NTFaFw00OTA0MTYxOTM1NTFaMEYxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5h
-bWUucGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEA6+8IYKAFnZ7V+fDo1cyMpbGBLzCfJOQ/1o2jOGP4+GjpsZgv6S6UT2MheC8M
-iiEFrYwdsSIZyYc3jEZrluy/UuR0bCGtqU92BCqa0iBLhvHOgjR588u253eLxQtQ
-8iJn11QPrKMk35nMkmY8GfHt4sGFbvBL6+GpipHq7a6cde3Z+v4kCB5dKMYDUDtm
-3mJmviuGNAu5wOqItk2Yi5dwJs1054007KNH0Il43urxiOfnkLS0cG5kehboPf86
-vxBt3iHByrU/9/DY5IvQCfSXVNa6rb5w5/pGja9aCei6Mv1jQY/V8SMQTga+MOsA
-0WB9akxMi2NxwS2+BQ4k/McPlwIDAQABoyUwIzAhBgNVHREEGjAYhwTAAAIBhxAg
-AQ24AAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQAQLo2RzC07dG9p+J3A
-W6C0p3Y+Os/YE2D9wfp4TIDTZxcRUQZ0S6ahF1N6sp8l9KHBJHPU1cUpRAU1oD+Y
-SqmnP/VJRRDTTj9Ytdc/Vuo2jeLpSYhVKrCqtjqIrCwYJFoYRmMoxTtJGlwA0hSd
-kwo3XYrALPUQWUErTYPvNfDNIuUwqUXNfS0CXuIOVN3LJ+shegg6Pwbh9B5T9NHx
-kH+HswajhdpdnZIgh0FYTlTCPILDrB49aOWwqLa54AUA6WXa35hPsP8SoqL9Eucq
-ifPhBYyadsjOb+70N8GbbAsDPN1jCX9L8RuNcEkxSCKCYx91cWXh7K5KMPuGlzB7
-j8xB
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjNaGA8yMDUwMTEyODE0MzUyM1owRjEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMSQwIgYDVQQDDBtjb21tb24t
+bmFtZS5wZy1zc2x0ZXN0LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDr7whgoAWdntX58OjVzIylsYEvMJ8k5D/WjaM4Y/j4aOmxmC/pLpRPYyF4
+LwyKIQWtjB2xIhnJhzeMRmuW7L9S5HRsIa2pT3YEKprSIEuG8c6CNHnzy7bnd4vF
+C1DyImfXVA+soyTfmcySZjwZ8e3iwYVu8Evr4amKkertrpx17dn6/iQIHl0oxgNQ
+O2beYma+K4Y0C7nA6oi2TZiLl3AmzXTnjTTso0fQiXje6vGI5+eQtLRwbmR6Fug9
+/zq/EG3eIcHKtT/38Njki9AJ9JdU1rqtvnDn+kaNr1oJ6Loy/WNBj9XxIxBOBr4w
+6wDRYH1qTEyLY3HBLb4FDiT8xw+XAgMBAAGjZTBjMCEGA1UdEQQaMBiHBMAAAgGH
+ECABDbgAAAAAAAAAAAAAAAEwHQYDVR0OBBYEFG+mujVw0u9XhfSYVs8/XJPwFCmF
+MB8GA1UdIwQYMBaAFPKPOmZAUGRIItcugv9WnsKz7nQKMA0GCSqGSIb3DQEBCwUA
+A4IBAQAm0M+VY4eZwfu47OPdiIJ4YxyGtcRCDDCuqZ8ACG7YH51Trhvm7SuHhGVQ
+aJvphWDPrt4e0Exmga0T8RJ2Xd49F9u21/biz+vvzdjpzcr3yd9YGQ2IoU35b3ln
+AVVB36i38eAOxYpSsv4CN01ilJYxhMdUQqRYjlagIYIp7dBwuQ7+uXUesBY6xgL/
+N0G+cUQuax8mokVB0HfNccbroXpJaz3fU1TSPiDgin7yMGkm9bTwj30pbesBOTID
+MqdYNodA7RIZslnmHn7q1rsGIBVUHrxUyH7/4m9ZbhI1Zz0VkoWAPklkqCO7moIb
+/oB/DmtwTndVB0urbGnEDzaoCntL
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-only+server_ca.crt b/src/test/ssl/ssl/server-cn-only+server_ca.crt
index 9870e8c17a..71ede03546 100644
--- a/src/test/ssl/ssl/server-cn-only+server_ca.crt
+++ b/src/test/ssl/ssl/server-cn-only+server_ca.crt
@@ -1,38 +1,41 @@
-----BEGIN CERTIFICATE-----
-MIIDAzCCAesCCCAhAwMUEgcBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDBTCCAe0CCCAjBxMWNSMCMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBGMR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxJDAiBgNVBAMMG2NvbW1vbi1uYW1lLnBn
-LXNzbHRlc3QudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWz
-VPMk7i5f+W0eEadRE+TTAtsIK08CkLMUnjs7zJkxnnm6RGBXPx6vK3AkAIi+wG4Y
-mXjYP3GuMiXaLjnWh2kzBSfIRQyNbTThnhSu3nDjAVkPexsSrPyiKimFuNgDfkGe
-5dQKa9Ag2SuVU4vd9SYxOMAiIFIC4ts4MLWWJf5D/PehdSuc0e5Me+91Nnbz90nl
-ds4lHvuDR+aKnZlTHmch3wfhXv7lNQImIBzfwl36Kd/bWB0fAEVFse3iZWmigaI/
-9FKh//WIq43TNLxn68OCQoyMe/HGjZDR/Xwo3rE6jg6/iAwSWib9yabfYPKbqq2G
-oFy6aYmmEquaDgLuX7kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA2AZrD9cTQXTW
-4j2tT8N/TTc6WK2ncN4h22NTte6vK7MVwsZJCtw5ndYkmxcWkXAqiclzWyMdayds
-WOa12CEH7jKAhivF4Hcw3oO3JHM5BA6KzLWBVz9uZksOM6mPqn29DTKvA/Y1V8tj
-mxK/KUA68h/u6inu3mo4ywBpb/tqHxxg2cjyR0faCmM0pwRM0HBr/16fUMfO83nj
-QG8g9J/bybu5sYso/aSoC5nUNp4XjmDMdVLdqg/nTe/ejS8IfFr0WQxBlqooqFgx
-MSE+kX2e2fHsuOWSU/9eClt6FpQrwoC2C8F+/4g1Uz7Liqc4yMHPwjgeP9ewrrLO
-iIhlNNPqpQ==
+Y2VydHMwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEYxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5hbWUu
+cGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+1bNU8yTuLl/5bR4Rp1ET5NMC2wgrTwKQsxSeOzvMmTGeebpEYFc/Hq8rcCQAiL7A
+bhiZeNg/ca4yJdouOdaHaTMFJ8hFDI1tNOGeFK7ecOMBWQ97GxKs/KIqKYW42AN+
+QZ7l1Apr0CDZK5VTi931JjE4wCIgUgLi2zgwtZYl/kP896F1K5zR7kx773U2dvP3
+SeV2ziUe+4NH5oqdmVMeZyHfB+Fe/uU1AiYgHN/CXfop39tYHR8ARUWx7eJlaaKB
+oj/0UqH/9YirjdM0vGfrw4JCjIx78caNkNH9fCjesTqODr+IDBJaJv3Jpt9g8puq
+rYagXLppiaYSq5oOAu5fuQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCT3LdsDzwy
+oKaXNuOgtENp4Pp4hLDXeZsepemYss75xfPsXyni9gWVTPIwwzq7NMawtP5q7zzB
+zUMiDgsL9J3d1kDcL0qbJV7xciwCA5D0O1EFKSogJK9jgdupswQZKNrEtM2F68mN
+SJ2aCJtIX/4lZb9KyRli4PDECrFjJM4vDQa9y05O5YY7lohvY5jubAAgexLT/n5r
+oycpw3xNzwGIQ8dAtjvtgONFFKAogWomFaCjWSBPW3ZVz4NM7CryH6oyxkUv/v+q
+/7vUykX0qBn7Vnk3nvVsqrqRRCbYXMz8qgMLeeXi5JjSeWDpYoiblIEfpf3FdtqS
+FnIQVHtAuZHb
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-only.crt b/src/test/ssl/ssl/server-cn-only.crt
index acdf6f1a75..6429529226 100644
--- a/src/test/ssl/ssl/server-cn-only.crt
+++ b/src/test/ssl/ssl/server-cn-only.crt
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDAzCCAesCCCAhAwMUEgcBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDBTCCAe0CCCAjBxMWNSMCMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBGMR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxJDAiBgNVBAMMG2NvbW1vbi1uYW1lLnBn
-LXNzbHRlc3QudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWz
-VPMk7i5f+W0eEadRE+TTAtsIK08CkLMUnjs7zJkxnnm6RGBXPx6vK3AkAIi+wG4Y
-mXjYP3GuMiXaLjnWh2kzBSfIRQyNbTThnhSu3nDjAVkPexsSrPyiKimFuNgDfkGe
-5dQKa9Ag2SuVU4vd9SYxOMAiIFIC4ts4MLWWJf5D/PehdSuc0e5Me+91Nnbz90nl
-ds4lHvuDR+aKnZlTHmch3wfhXv7lNQImIBzfwl36Kd/bWB0fAEVFse3iZWmigaI/
-9FKh//WIq43TNLxn68OCQoyMe/HGjZDR/Xwo3rE6jg6/iAwSWib9yabfYPKbqq2G
-oFy6aYmmEquaDgLuX7kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA2AZrD9cTQXTW
-4j2tT8N/TTc6WK2ncN4h22NTte6vK7MVwsZJCtw5ndYkmxcWkXAqiclzWyMdayds
-WOa12CEH7jKAhivF4Hcw3oO3JHM5BA6KzLWBVz9uZksOM6mPqn29DTKvA/Y1V8tj
-mxK/KUA68h/u6inu3mo4ywBpb/tqHxxg2cjyR0faCmM0pwRM0HBr/16fUMfO83nj
-QG8g9J/bybu5sYso/aSoC5nUNp4XjmDMdVLdqg/nTe/ejS8IfFr0WQxBlqooqFgx
-MSE+kX2e2fHsuOWSU/9eClt6FpQrwoC2C8F+/4g1Uz7Liqc4yMHPwjgeP9ewrrLO
-iIhlNNPqpQ==
+Y2VydHMwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEYxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5hbWUu
+cGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+1bNU8yTuLl/5bR4Rp1ET5NMC2wgrTwKQsxSeOzvMmTGeebpEYFc/Hq8rcCQAiL7A
+bhiZeNg/ca4yJdouOdaHaTMFJ8hFDI1tNOGeFK7ecOMBWQ97GxKs/KIqKYW42AN+
+QZ7l1Apr0CDZK5VTi931JjE4wCIgUgLi2zgwtZYl/kP896F1K5zR7kx773U2dvP3
+SeV2ziUe+4NH5oqdmVMeZyHfB+Fe/uU1AiYgHN/CXfop39tYHR8ARUWx7eJlaaKB
+oj/0UqH/9YirjdM0vGfrw4JCjIx78caNkNH9fCjesTqODr+IDBJaJv3Jpt9g8puq
+rYagXLppiaYSq5oOAu5fuQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCT3LdsDzwy
+oKaXNuOgtENp4Pp4hLDXeZsepemYss75xfPsXyni9gWVTPIwwzq7NMawtP5q7zzB
+zUMiDgsL9J3d1kDcL0qbJV7xciwCA5D0O1EFKSogJK9jgdupswQZKNrEtM2F68mN
+SJ2aCJtIX/4lZb9KyRli4PDECrFjJM4vDQa9y05O5YY7lohvY5jubAAgexLT/n5r
+oycpw3xNzwGIQ8dAtjvtgONFFKAogWomFaCjWSBPW3ZVz4NM7CryH6oyxkUv/v+q
+/7vUykX0qBn7Vnk3nvVsqrqRRCbYXMz8qgMLeeXi5JjSeWDpYoiblIEfpf3FdtqS
+FnIQVHtAuZHb
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-crldir/a836cc2d.r0 b/src/test/ssl/ssl/server-crldir/a836cc2d.r0
index 331a83cb62..7ed68e0220 100644
--- a/src/test/ssl/ssl/server-crldir/a836cc2d.r0
+++ b/src/test/ssl/ssl/server-crldir/a836cc2d.r0
@@ -1,11 +1,11 @@
-----BEGIN X509 CRL-----
-MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
-MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
-MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
-+10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
-4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
-ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
-imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
-B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+MIIBpzCBkDANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowGzAZAgggIwcTFjUjCxcNMjMwNzEz
+MTQzNTI0WjANBgkqhkiG9w0BAQsFAAOCAQEADIkF8oS84O2PJw/C9BAzgrkd+EsO
+QL6mXUGBgXwmujfpv0Z8YK91k4+xV9hQRMjWe/DkU01+gmFhYoDvAzweuNQzx8lZ
+bYKu0dGTEpTd+OG1LbxYmt4f5xh096R5iLo7c7e2kMHvfNG7VwvKQrPeMqh7AcKy
+Fukt8C0Xc7Tfv2l2toEQUAl5UDUKEAovN6iB0qycpvi0nboyiDo8mV0p1jlAn846
+EeXjwm8tyGXzTFq16ypPwnlBM9d5Ml/p5WTN69nDux18G+iSCr+UDzLDYvLF11p3
+lEqpSo5lQg9zYuOgMCvu3g5BtwJgORPSiW/yZ5BXUfWvPi0XRPrknxMByA==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/server-ip-alt-names.crt b/src/test/ssl/ssl/server-ip-alt-names.crt
index 8a1bc620bb..3f15775a34 100644
--- a/src/test/ssl/ssl/server-ip-alt-names.crt
+++ b/src/test/ssl/ssl/server-ip-alt-names.crt
@@ -1,19 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDCTCCAfGgAwIBAgIIICERKREEUAAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDSzCCAjOgAwIBAgIIICMHExY1IwMwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTExMjkxOTA0NTBaFw00OTA0MTYxOTA0NTBaMCAxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAOM8yB6aVWb17ujr3ayU62mxHQoqn4CvG9yXlJvGOGv/ursW
-Vs0UYJdc96LsNZN1szdm9ayNzCIw3eja+ULsjxCi6+3LM4pO76IORL/XFamlTPYb
-BZ4pHdZVB0nnZAAnWCZPyXdnjOKQ5+8unVXkfibkjj8UELBJ2snehsOa+CTkOBez
-zxYMqxAgbywLIYsW448brun7UXpWmqbGK+SsdGaIZ5Sb7Zezc5lt6CrLemTZTHHK
-7l4WZFCCEi4t3sgO8o1vDELD/IE5G8lyXvIdgJg6t8ssper7iCw6S8x+okhjiSjT
-vDLU2g4AanqZRZB49aPwTo0QUcJA2BCJxL9xLy8CAwEAAaMlMCMwIQYDVR0RBBow
-GIcEwAACAYcQIAENuAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAwZJ+
-8KpABTlMEgKnHIYb35ItGhtFiTLQta9RkXx7vaeDwpOdPP/IvuvpjpQZkobRgBsk
-bNM0KuJpd2mSTphQAt6eKQIdcPrkzvc/Yh9OK3YNLUAbu/ZhBUnBvFnUL4wn2f1U
-mfO+m8P/LxybwqKx7r1mbaB+tP3RTxxLcIMvm9ECPQEoBntfEL325Wdoj+WuQH5Y
-IvcM6FaCTkQsNIPbaBD5l5MhMLHRULZujbDjXqGSvRMQfns6np/biMjNdQA8NZ5z
-STeUFvkQbCxoA0YYLgoSHL5KhZjXrg2g+T+2TUyCTR/91xf9OoOjBZdixR0S0DzJ
-B1+5vnUjZaCfnSEA7A==
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjNaGA8yMDUwMTEyODE0MzUyM1owIDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA4zzIHppVZvXu6OvdrJTrabEdCiqfgK8b3JeUm8Y4a/+6
+uxZWzRRgl1z3ouw1k3WzN2b1rI3MIjDd6Nr5QuyPEKLr7cszik7vog5Ev9cVqaVM
+9hsFnikd1lUHSedkACdYJk/Jd2eM4pDn7y6dVeR+JuSOPxQQsEnayd6Gw5r4JOQ4
+F7PPFgyrECBvLAshixbjjxuu6ftRelaapsYr5Kx0ZohnlJvtl7NzmW3oKst6ZNlM
+ccruXhZkUIISLi3eyA7yjW8MQsP8gTkbyXJe8h2AmDq3yyyl6vuILDpLzH6iSGOJ
+KNO8MtTaDgBqeplFkHj1o/BOjRBRwkDYEInEv3EvLwIDAQABo2UwYzAhBgNVHREE
+GjAYhwTAAAIBhxAgAQ24AAAAAAAAAAAAAAABMB0GA1UdDgQWBBSZsk0rfkcawCvx
+XxCfQdMrWBIAVTAfBgNVHSMEGDAWgBTyjzpmQFBkSCLXLoL/Vp7Cs+50CjANBgkq
+hkiG9w0BAQsFAAOCAQEAHtiw75o40lNQJPmdNJ0GijokFQ80AB9Cq1h3IAE7g9X4
+S5EQ+xukQoEcDwqi3PYN2axHayE3qgYpD4burydxboNFeDSl06Sv+g3KQ57Uv76y
+ODFOElKwedkdfgxVrBNX2kVR1gacQHrMqGN7aBSwZ8wReLS4keYtDo/Bfd9cyaBF
+g3CuPCa7u7ZB9S+g8bRE1L0rktQ9viynMI5G1hgFqm+aXMBpWrQj566z8qMRDN0a
+qk6gHxfXFy9NJorUxfHOTcrrKA2YciGHFUdRZT6zX4Nt8RjTWK6Oxro4G6UqAH+2
+g65OIDeyMwi+UUnDzMQPJoI20jZpBms9670yrlZDqg==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt b/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt
index 2be02feb03..cbf79b9112 100644
--- a/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt
+++ b/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt
@@ -1,19 +1,21 @@
-----BEGIN CERTIFICATE-----
-MIIDHTCCAgWgAwIBAgIIICIBBBQ2MQAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDXzCCAkegAwIBAgIIICMHExY1IwUwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMjAxMDQyMjM2MzFaFw00OTA1MjIyMjM2MzFaMDQxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTESMBAGA1UEAwwJMTkyLjAuMi4x
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwmqTdQJfs2Ti9tPitYp2
-27I0HvL/kNSgA6egFr0foRo0BorwJNIzdbV0+EnsfiBNTWL5It26gqO7UP3ms8t2
-vHD5gkXfT+f6ts0lVJEcIOkUD/8ws4Ic9Y4uPqb4gN+pUKqcxtmLW1TYk84MBK59
-Xz4yPPS6N+G/DMMeFHTNkM9EQwn/+DC3fDsWdGYM2GRWDTJGg1A5tSUcF+seu7i1
-Vg7XajBfsvgAUAsrAxV+X/sLZh94HY+paD6wfaI99mY2OXVc/XW/z1r9WQznor65
-ZkonNCaPfavqPG5vqnab9AyQcqPqmX8hf/xrniASBAkqNCctbASrFCIYvCJfGfmX
-EQIDAQABoyUwIzAhBgNVHREEGjAYhwTAAAIChxAgAQ24AAAAAAAAAAAAAAABMA0G
-CSqGSIb3DQEBCwUAA4IBAQBf7kmYfRYfnWk1OUfY3N1kaNg9piBBlFr9g+OQn9KU
-zirkN7s0ZQbCGxV1uJQBKS58NyE414Vorau77379emgYDcCBpDIYpkLiNujVrIOr
-ggRFKsFRgxu4/mw0BSgCcV8RPe9SWHZ90Mos7TMCnW/PdxOCD1wD0YMkcs0rwB3l
-0Kzc7jDnfOEvmgw/Ysm7v67ps+05Uq5VskQ6WrpSAw6kPD/QMuuBAX8ATPczIaox
-zAMyncq1IiSIwG93f3EoQQThdQ70C6G9vLcu9TtL6JAsEMFEzR99gt1Wsqvmgl9W
-kStzj1yjIWeo5gIsa4Jgcke1lZviWyrTxHDfyunYE5i5
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMRIwEAYDVQQDDAkxOTIuMC4y
+LjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCapN1Al+zZOL20+K1
+inbbsjQe8v+Q1KADp6AWvR+hGjQGivAk0jN1tXT4Sex+IE1NYvki3bqCo7tQ/eaz
+y3a8cPmCRd9P5/q2zSVUkRwg6RQP/zCzghz1ji4+pviA36lQqpzG2YtbVNiTzgwE
+rn1fPjI89Lo34b8Mwx4UdM2Qz0RDCf/4MLd8OxZ0ZgzYZFYNMkaDUDm1JRwX6x67
+uLVWDtdqMF+y+ABQCysDFX5f+wtmH3gdj6loPrB9oj32ZjY5dVz9db/PWv1ZDOei
+vrlmSic0Jo99q+o8bm+qdpv0DJByo+qZfyF//GueIBIECSo0Jy1sBKsUIhi8Il8Z
++ZcRAgMBAAGjZTBjMCEGA1UdEQQaMBiHBMAAAgKHECABDbgAAAAAAAAAAAAAAAEw
+HQYDVR0OBBYEFGX9z+RX7x23a5ViEQbcj5XBGHaZMB8GA1UdIwQYMBaAFPKPOmZA
+UGRIItcugv9WnsKz7nQKMA0GCSqGSIb3DQEBCwUAA4IBAQCQQ+5/h6r84jks/l5u
+0G6w07hcgo/AfPEVSqGXDlEiJEdP8IownmxPB5siRwq6FNHqVMQ6usFeTlfYqtzE
+OmQOagLyKAhYCQkVPUIpIKLj70o8DVqnwoxr1+kWZUi4xLPTYPawFHUem7cX6TuT
+7TQe2yCXPHf8GaIMRjNI1LSpT5DUxHXZinw6UnsHr5EotFTSzmS/Yfko881+WDBq
+Uv/AOReEwLUvaRBTbWmIxyN7y6S8BUzlDw6AvSZLVczuQ1qLbFAc/fjdkiyCos2J
+r8FOq7UnBrvbs7/mT/1AtAcHjShPYGH3JFIgvHfixrJlsdS85f3GA9tJgJ9BV16d
+qkjO
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt b/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt
index 23c06da01c..b51dab2963 100644
--- a/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt
+++ b/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt
@@ -1,20 +1,21 @@
-----BEGIN CERTIFICATE-----
-MIIDQzCCAiugAwIBAgIIICIBBBQ2MQEwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDhzCCAm+gAwIBAgIIICMHExY1IwYwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMjAxMDQyMjM2MzFaFw00OTA1MjIyMjM2MzFaMDQxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTESMBAGA1UEAwwJMTkyLjAuMi4x
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8xddbo/x2TOSIa/br8BN
-o/URdTr9+l2R5YojiZKDuLxiQVkgC30PJ2/CNFKIh2nHhRrzknI6sETVtrxZ+9V2
-qRc1yShVu462u0DHPRMIZnZIOZg3hlNB0cRWbOglUKlttIARNEQUcTUyPOtyo4/v
-+u0Ej5NTNcHFbFT01vdD9MjQiCO3jKdAwPIb14jTg4C71EpZ+LuelDo4DzF2/XgG
-WqUTrgD/XnBU/60PU9Iy3G0nVpx21q6ppn9G7a9R+i8FjBcwW1T+cfsBDWhAv+bi
-RmSAkENf8L8TwOlDQUwROkfz3Hz36vuJjdkreQJsiqL0HnrnH5T5G9UzJO86FvZQ
-5wIDAQABo0swSTBHBgNVHREEQDA+gh1kbnMxLmFsdC1uYW1lLnBnLXNzbHRlc3Qu
-dGVzdIIdZG5zMi5hbHQtbmFtZS5wZy1zc2x0ZXN0LnRlc3QwDQYJKoZIhvcNAQEL
-BQADggEBAF+mfaw6iBPzpCgqq830pHRa3Yzm1aezt8SkeRohUYHNv/yCnDSRaqtj
-xbENih3lJMSTBL3g0wtTOHfH8ViC/h+lvYELHzXKic7gkjV7H5XETKGr0ZsjBBT2
-4cZQKbD9e0x0HrENXMYgGpBf747qL6uTOVJdG0s15hwpLq47bY5WUjXathejbpxW
-prmF8F+xaC52N9P/1VnqguQB909F4x1pyOK7D7tjFu+Y8Je7PHKbb6WY5K6xAv6t
-R17CY0749/FotlphquElUR2bs5Zzv5YrjUHPTcbwKvcH5cdNi93/u6NJt2xNAoYf
-aZERhX5TA9DYk4gC8OY0yGaYCIj3Dd4=
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMRIwEAYDVQQDDAkxOTIuMC4y
+LjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDzF11uj/HZM5Ihr9uv
+wE2j9RF1Ov36XZHliiOJkoO4vGJBWSALfQ8nb8I0UoiHaceFGvOScjqwRNW2vFn7
+1XapFzXJKFW7jra7QMc9Ewhmdkg5mDeGU0HRxFZs6CVQqW20gBE0RBRxNTI863Kj
+j+/67QSPk1M1wcVsVPTW90P0yNCII7eMp0DA8hvXiNODgLvUSln4u56UOjgPMXb9
+eAZapROuAP9ecFT/rQ9T0jLcbSdWnHbWrqmmf0btr1H6LwWMFzBbVP5x+wENaEC/
+5uJGZICQQ1/wvxPA6UNBTBE6R/PcfPfq+4mN2St5AmyKovQeeucflPkb1TMk7zoW
+9lDnAgMBAAGjgYwwgYkwRwYDVR0RBEAwPoIdZG5zMS5hbHQtbmFtZS5wZy1zc2x0
+ZXN0LnRlc3SCHWRuczIuYWx0LW5hbWUucGctc3NsdGVzdC50ZXN0MB0GA1UdDgQW
+BBSAWxUeTAXIo1H+cmx5bW0UJrPWlDAfBgNVHSMEGDAWgBTyjzpmQFBkSCLXLoL/
+Vp7Cs+50CjANBgkqhkiG9w0BAQsFAAOCAQEAoFdBPGtQA1y8lVAK3aFMyczeFwmS
+Bh+gIEyYpzWEUCgLManf6MnVpR1lG2nPasHawlHD0vmNBNuKHaKwtvXanNlnhK60
+mSyVx2tRVtygs+fCFykS3Oy0GlBWdoONyZWmwV97+Jpq7F2tb3fqCehy0HWFKruG
+JfVFBfVtPOdEgrla6ExuVcitDGNjKe6O1Kvt5m2Ze5+tX/rBJcSL9vfh/pa/qM4B
+lukCT9RwNNfUgNKIC0Tq13sNUeo7Fz3td46ZFOviBMv5ywH/7OE9eYNRvXwd/brH
+xNiRiUwBiUMvae38Tm4E8bFT6N/pmRVXAk4v84Eo/hxFIogT531JNaQhYA==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-cn-only.crt b/src/test/ssl/ssl/server-ip-cn-only.crt
index 9bf015cf18..8b15358577 100644
--- a/src/test/ssl/ssl/server-ip-cn-only.crt
+++ b/src/test/ssl/ssl/server-ip-cn-only.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC8TCCAdkCCCAhESkRN1IAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC8zCCAdsCCCAjBxMWNSMEMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjExMTI5MTkzNzUyWhcNNDkwNDE2MTkzNzUyWjA0MR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxEjAQBgNVBAMMCTE5Mi4wLjIuMTCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWs1uUL71nHYF9Zj6p+M3MpYDvx
-32iCjVdtH5a2qpSWHXTg0rR8dLX0y92cvOYvMXHRajZT1avpHr8dooPYSVaXpGMK
-NvF/Qi+WFYovRbP2vmd1yv1cgW/FggbwJFWVobizIz4seyA4d0B2j9fqoi2OFBNP
-huW664SjF0u3p21tDy+43i2LNUMAKf6dnRR5Vqenath87LEU41tSLudu6NXgbFMk
-jvfNkl4d0w7YCzeXmklmSI+uaX3PlJJ4NzQO2j8w5BvnKVhNVD0KjgrXZ6nB/8F7
-Pg3XY+d7rJlwRgXemU6resWQDJ7+UaC9u7I4EIP+9lzCR/nNBqUktpHRmHUCAwEA
-ATANBgkqhkiG9w0BAQsFAAOCAQEAos1JncV8Yf4UaKl6h1GdYtcVtzFyJvBEnhRD
-07ldL+TYnfZiX8wK2ssBtM3cg/C78y5bzdUa5XGS83ZKQJFFdhE7PSnrvyNqyIqY
-ZgNBxto3gyvir+EjO1u9BAB0NP3r3gYoHRDZS1xOPPzt4WgjuUgTLM9k82GsqAbO
-UrOTOdRnkIqC5xLpa05EnRyJPRsR1w1PRJC2XXKnHIuFjMb4v7UuPwyCcX1P5ioc
-rQszQcORy/L+k0ezCkyweORg68htjYbBHuwOuiGfok6yKKDMzrTvD3lIslls6eX7
-4sI3XWqzkPmG9Vsxm9Vu9/Ma+PRO76VyCoIwBd+Ufg5vNXhMmw==
+Y2VydHMwIBcNMjMwNzEzMTQzNTI0WhgPMjA1MDExMjgxNDM1MjRaMDQxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTESMBAGA1UEAwwJMTkyLjAuMi4xMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1azW5QvvWcdgX1mPqn4zcylg
+O/HfaIKNV20flraqlJYddODStHx0tfTL3Zy85i8xcdFqNlPVq+kevx2ig9hJVpek
+Ywo28X9CL5YVii9Fs/a+Z3XK/VyBb8WCBvAkVZWhuLMjPix7IDh3QHaP1+qiLY4U
+E0+G5brrhKMXS7enbW0PL7jeLYs1QwAp/p2dFHlWp6dq2HzssRTjW1Iu527o1eBs
+UySO982SXh3TDtgLN5eaSWZIj65pfc+Ukng3NA7aPzDkG+cpWE1UPQqOCtdnqcH/
+wXs+Dddj53usmXBGBd6ZTqt6xZAMnv5RoL27sjgQg/72XMJH+c0GpSS2kdGYdQID
+AQABMA0GCSqGSIb3DQEBCwUAA4IBAQB2VbIjlzU7ieisvO3ZCGMJmCmQtEDC8Xgo
+umbbHtCdCYtPy8KSulAKBzLLBpVsQiOqq6T8t3KZrU64Wi2DEamULfYfgZCdatQw
+EWzBmTOO+5guo3ntm57+3kR9pRbTDbLUgOrgJrKnu1THof+6gwX6e0D++91mfwpm
+FLhn4bIuRyQtlqH7Ft0otsA4HezoHDLGTS76NDYpx+rDklFE6ZUk3RFgC7ScXPfW
+rA+KJIATgnrDwBx+n8s1SeZ7S64QkZk27QVi/8exYbd6aJwWBTuoHXZswfn5nK/b
+PFR7RK0LgucLvOKjUTzNPZUyhjS+b2dSnPZUuWNTFFu5KhnfoPEZ
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-in-dnsname.crt b/src/test/ssl/ssl/server-ip-in-dnsname.crt
index 78ad8d99c8..87009ebd2c 100644
--- a/src/test/ssl/ssl/server-ip-in-dnsname.crt
+++ b/src/test/ssl/ssl/server-ip-in-dnsname.crt
@@ -1,18 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIC/DCCAeSgAwIBAgIIICIDFRVYUgAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDPjCCAiagAwIBAgIIICMHExY1IwcwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMjAzMTUyMjU4NTJaFw00OTA3MzEyMjU4NTJaMCAxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAMpn5bP1/OfBQR/yvOkOBzxArE1j1YShVa2pcj896+CVDEgV
-N5Hluz7KHU/JYzNZCAHb5WAHuvXxKeoj4Ti5be1KsqO0mN1p+RMN7VlCpCpb0AWT
-z4z+I8TUhSZnmgghHvfW4RfcZMCcHq1vevVTDxR/cAbDPYpgBCD5F/SZMRyMDw5B
-7ILLmft0eqA1nCqavyqBCGZvx1ol8N5BfVdrDXp/rN5997khBWQRZ8g84FZyFZXf
-pwp57eu0OGQDzZFXoEL2t4OVld67K5jcclWVxHY6FGcHjCvyqs48PCPOR84anZwj
-GsqVOS6250/DWKBQO4KyhkTVf0AW/ICGSMOKkAkCAwEAAaMYMBYwFAYDVR0RBA0w
-C4IJMTkyLjAuMi4xMA0GCSqGSIb3DQEBCwUAA4IBAQDIAAH0WJKEpbPN0QihN6SF
-UA5WL4ixsBACo9OIAGkSnKeOeVEG5vvgOna0hjQcOcgtI1oCDLhULcjCuwxiIW6y
-QntOazyo0sooJr0hEm2WfipvIpQs6W9E1OTcs624BAVfkAwr6WT2VwoIAPcQD2nR
-tIQhSUIR9J7Q5WbzuQw7pthQhBfW/UPWw7vajel0r1dflbe0Cgp5WGNfp1kYy+Qf
-XW/YjkstZEP1KFm+TF58uxrIDmYboS8EerUREGQixijbI0AfXjShxtiyS63rbdpo
-3C0BPj9Yx2VtWi4U0qoef/iLJxJBCLvE/97+duPdKx0AkkOWA9VuenkWLp797UM8
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowIDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAymfls/X858FBH/K86Q4HPECsTWPVhKFVralyPz3r4JUM
+SBU3keW7PsodT8ljM1kIAdvlYAe69fEp6iPhOLlt7Uqyo7SY3Wn5Ew3tWUKkKlvQ
+BZPPjP4jxNSFJmeaCCEe99bhF9xkwJwerW969VMPFH9wBsM9imAEIPkX9JkxHIwP
+DkHsgsuZ+3R6oDWcKpq/KoEIZm/HWiXw3kF9V2sNen+s3n33uSEFZBFnyDzgVnIV
+ld+nCnnt67Q4ZAPNkVegQva3g5WV3rsrmNxyVZXEdjoUZweMK/Kqzjw8I85Hzhqd
+nCMaypU5LrbnT8NYoFA7grKGRNV/QBb8gIZIw4qQCQIDAQABo1gwVjAUBgNVHREE
+DTALggkxOTIuMC4yLjEwHQYDVR0OBBYEFDGGF+fm5mk/sd23jkLL3uVU0NjCMB8G
+A1UdIwQYMBaAFPKPOmZAUGRIItcugv9WnsKz7nQKMA0GCSqGSIb3DQEBCwUAA4IB
+AQCf8knuWhoBZ8psmq+NC/RZRxfQmFBRj+bKzJ6YaAHyNmE44nBtIAJal3m4FyTZ
+vXAlYpfRLrF+R5PJVnvT8mfu/vfxJn3MPHV7R8vmJpRAx8uQKFuxQPQDUq84efqZ
+BHG0zoNPml915nVfxgt1WqIVWQpomAOvjb1Ct31A1bZF5oMjhg86XdytqQNohl8I
+NBNu027tO0izM/mX3xJzYEnBSiHwKPfZxSKtc0FSffwohWUlpEye1A4Q9d6tWF6d
++PagUG+hodSLsU5Bno4dc0RYJr9xJLW9QMcuCbMC9zXaUBWpkUwOWbMXpPhvawdu
+oR2Tvhha37JD6a8NEUgSJOvL
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-multiple-alt-names.crt b/src/test/ssl/ssl/server-multiple-alt-names.crt
index 58799e49f8..85663b97af 100644
--- a/src/test/ssl/ssl/server-multiple-alt-names.crt
+++ b/src/test/ssl/ssl/server-multiple-alt-names.crt
@@ -1,20 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIDSzCCAjOgAwIBAgIIICEDAxQSBwMwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDjzCCAnegAwIBAgIIICMHExY1IwkwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTAzMDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMCAxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBANdIkKX1X+Jwqo5EXC1z/TjUKnYTDzHYx2rCqprBU8fN0mSy
-lMyjDm+eo924PN7LahqCHeDCMbapwymkoNfpLHkNRwotHLvxN5RyxJD4m5fXclRo
-V1ZzwwXTqXlECwrzzYGst/7muDM9DX+0vXIAvQGbvxBGI0CBM3ztHBADXlSFrYGX
-zN/to9KZmeOgBGJRGSZJg09P5px5N2E49yOqkIa9+MGb6nK8KLmETeTYjlWCS6W+
-oD0qGpZvj2Fzioz+Pn1q9fB3WS687GuMT0WvV3LAzcn341r0E36bUf9rxSjfBX79
-11KsVMemr1QskSmvMQFEv6R1Rp8xUGPqKlkRJ9sCAwEAAaNnMGUwYwYDVR0RBFww
-WoIdZG5zMS5hbHQtbmFtZS5wZy1zc2x0ZXN0LnRlc3SCHWRuczIuYWx0LW5hbWUu
-cGctc3NsdGVzdC50ZXN0ghoqLndpbGRjYXJkLnBnLXNzbHRlc3QudGVzdDANBgkq
-hkiG9w0BAQsFAAOCAQEAuRAyYBwAZLKERoYDy/kE9LKddJfLhledTJ7+cIWs6T9V
-KBfWBHZYxfxmdBYwqVZfog8c5uHREfWiUPoF/aMq3ARay96aMh4xXJ+2a7HAmknF
-9AJWRieoc3H/QkMzAuT8IDTmoEarsr8vsX1MGabobZte/B9tEjq/z5t3GfLrHMVX
-5092U6Ka40ii4U1VwjR8YnRBwjm3UpLmZJAjvXjw13/XucNV5O8Plo1yvS+G0AMh
-KdMxExiItVtjZteiA0pJf0YGAzTFyzvwBljTcs4NfZ2M0ta9i0r4BF7wQ8tDezN7
-VxdJVPc5xPqncp0cMdUAE2xDmYlKEqB0kuAHNwH5/Q==
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowIDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA10iQpfVf4nCqjkRcLXP9ONQqdhMPMdjHasKqmsFTx83S
+ZLKUzKMOb56j3bg83stqGoId4MIxtqnDKaSg1+kseQ1HCi0cu/E3lHLEkPibl9dy
+VGhXVnPDBdOpeUQLCvPNgay3/ua4Mz0Nf7S9cgC9AZu/EEYjQIEzfO0cEANeVIWt
+gZfM3+2j0pmZ46AEYlEZJkmDT0/mnHk3YTj3I6qQhr34wZvqcrwouYRN5NiOVYJL
+pb6gPSoalm+PYXOKjP4+fWr18HdZLrzsa4xPRa9XcsDNyffjWvQTfptR/2vFKN8F
+fv3XUqxUx6avVCyRKa8xAUS/pHVGnzFQY+oqWREn2wIDAQABo4GoMIGlMGMGA1Ud
+EQRcMFqCHWRuczEuYWx0LW5hbWUucGctc3NsdGVzdC50ZXN0gh1kbnMyLmFsdC1u
+YW1lLnBnLXNzbHRlc3QudGVzdIIaKi53aWxkY2FyZC5wZy1zc2x0ZXN0LnRlc3Qw
+HQYDVR0OBBYEFNQECIqqAsJFZk9MZ3oygGNRbziXMB8GA1UdIwQYMBaAFPKPOmZA
+UGRIItcugv9WnsKz7nQKMA0GCSqGSIb3DQEBCwUAA4IBAQDOljab+EBwmJA4qzN4
+nY3QVQWxoPG7RBrNFRp2hrP05amitsjWG4+GWiIlKT7aSpEgUghdZgAb25FG44VH
+oUEo2aAJjTRGmssbeOUstDRXYCIOefaaxSleEgbZdrUb+zDkPwDw381EYuO/E+og
+OcS9nsbrq1vo1B09xQdpcJ6pf9VmmM4OQHpD2/xPxhOPVxMKhbrFvVOlHDc23sue
+kfaAnHFu3k5O2/fqGxWm7IQA8KNfhyWRDDZjwU3F+duqiHphGDyn0JH6bO+QNSEs
+kj7tCGh9oziomt/mnD1zDPO+s9f5+i9itk8emRaBakLsv7SyngO777r79myiiM+E
+LYJo
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-no-names.crt b/src/test/ssl/ssl/server-no-names.crt
index b5d0589090..45a434bcf1 100644
--- a/src/test/ssl/ssl/server-no-names.crt
+++ b/src/test/ssl/ssl/server-no-names.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC3TCCAcUCCCAhAwMUEgcEMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC3zCCAccCCCAjBxMWNSMKMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAgMR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQCfOf74edog2QHkJlreO6NJEe1VZUSxn+LBeHH8T5fniFiM4Ym9X2o3
-XKhYsvNSwvrfWwMkajMkd3b3vURiuiAxYzB/9AwX97RUkZ8TfuU3UgISiCbJZrVH
-TpfJEv7JhePgYpAoOdPWqtFPmnO/Xv6uNjsrx/V/3COovUj3eIcyQzAl+eC2U9Tn
-//dJ0kF+hDnOR3I/3e6bAboJjAVvLl2ABryaateHuUaCu/Bf5mG1DarXNXPKYuP+
-KrkjHhH0KQ4Js3nu7bPEiG0E/JmCR452j72WKb+PiJHOxdMMyztZ3k6bGGlbw60j
-CwQnUJAlPL4G9U+lpVYG6f7HxOaJEscfAgMBAAEwDQYJKoZIhvcNAQELBQADggEB
-AJAwYwIL4oj3NisXCXkEp9zqDXiZvNW9yW3bY8lFFCpU7o5n92tCf2OFAkKaYhF1
-Eb2weyDULtW7W/wgdlOZL9npayYKzTusl6e8xfTQyjRCsoKWvnWOEkPH7VraZJ8c
-Ko1KhaVWX98VLdlUh5giYAEkdhk0qPYKsQ32unBXXJu0pX63pnPDoaUBiZUWr/3l
-CfkjgGY5YA8YxiDlHGNF1qlcX2fQKloDlvtH0L5Enwt25w2/IvWhTN6YxDR+rgdD
-XYbQr6o6vsmnZTJ3zUZ6XFo98sZq5L9oy1pcC8roV7w0AUVxraTWYILyGfNgruG8
-xsok/hu1L2VnktveEW/qoVs=
+Y2VydHMwIBcNMjMwNzEzMTQzNTI0WhgPMjA1MDExMjgxNDM1MjRaMCAxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAJ85/vh52iDZAeQmWt47o0kR7VVlRLGf4sF4cfxPl+eIWIzhib1f
+ajdcqFiy81LC+t9bAyRqMyR3dve9RGK6IDFjMH/0DBf3tFSRnxN+5TdSAhKIJslm
+tUdOl8kS/smF4+BikCg509aq0U+ac79e/q42OyvH9X/cI6i9SPd4hzJDMCX54LZT
+1Of/90nSQX6EOc5Hcj/d7psBugmMBW8uXYAGvJpq14e5RoK78F/mYbUNqtc1c8pi
+4/4quSMeEfQpDgmzee7ts8SIbQT8mYJHjnaPvZYpv4+Ikc7F0wzLO1neTpsYaVvD
+rSMLBCdQkCU8vgb1T6WlVgbp/sfE5okSxx8CAwEAATANBgkqhkiG9w0BAQsFAAOC
+AQEA1w+EnZ8ef189KqulzF9vrKjdavlFyWon+otR0WAKFOojNMyIgAkbU69N0CHO
+LnJPiIF3H3izWelNo+2Wv3BxylQXgRlr92gUCFoEQ/RKnZVjgKl36e2+l/AVud1Q
+ke343xnYLup/jQ7LzKFIdyxmO090rrlHUO7Dg7bJAuHQ9bRbCO+orAg4nFZEoKd1
+kO/XQ7e18l95QJE6vOmRcbD0+kGRNYBA2v6K3DwX0PRUm7fyP1gLTbIt6jGukQiJ
+/ZkcvVcHNkcJzEr+A8BGVYgTG6VhuBPSMWVnnZcui93vH2D/3hq7ILNlFWBycSW6
+HheriPQ4X+y96SmttrjQVwSDYA==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-revoked.crt b/src/test/ssl/ssl/server-revoked.crt
index 3bb0f164a6..ce4350dbc6 100644
--- a/src/test/ssl/ssl/server-revoked.crt
+++ b/src/test/ssl/ssl/server-revoked.crt
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDAzCCAesCCCAhAwMUEgcFMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDBTCCAe0CCCAjBxMWNSMLMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBGMR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxJDAiBgNVBAMMG2NvbW1vbi1uYW1lLnBn
-LXNzbHRlc3QudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKKD
-zvJUs+N+KeDwWAW0zfI5C1t3BxKUwh+MrwtFeNIcxhJd9Bzy6fNnvpMa/kNPoHfN
-n73OGLYeSDyiDc56dvBjLOfxPXFFN4TCuIxYSizIjniL3tzP/a8hyvO+KqTYyaEs
-cT8+/rNnqlqBXNqcdChSGpk0y34uybvWj2/wDJWTbFJ20bI+30HOxCfK8Dp3s8Nl
-suVSuLKF/qqbidDZuOAKc0/GJo2F/5AF9MkMYELmG6XAVq/XDkI3oLtxQKh6kYfc
-nu3fI0Mwr9+FoP2q+K5KskA3KJLlgBOykG55Odbe6Js4TPHrMBTgC9aWrP/I1gb8
-tFY2FVN+D/Wl8T/Boh0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAxVHoqX25W4Hx
-pMNjv2AJzcB7D+c+dUXAmLLJ7jh6szWeL0M2E5qX4dLc8LzQKnXv5ZcT4i/akjDX
-etdzuqh03kvDJvUkHclSWffmowmWMTG6GCA6S/2TQzSibIptkwqs74aIkayVJaC4
-jCBR+PVT8+cE2FMD6dAWu//fyEcpTg6XpZ/Upgu9OITGNaEQUGz8pSRkTgspfO0Q
-AKPmql6dpywReIlr5mzy9liCzf/BbAVHGmP/pBGIkLn2AzvPLCQ/UFZYT6aH7l5J
-nzmFhgRC3U5wPMdelHGrPMXg6OHCcyrQY0kEi7N/GQ5+jZkICoQuPJ7APKEZAUgO
-XRwVulaWJQ==
+Y2VydHMwIBcNMjMwNzEzMTQzNTI0WhgPMjA1MDExMjgxNDM1MjRaMEYxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5hbWUu
+cGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+ooPO8lSz434p4PBYBbTN8jkLW3cHEpTCH4yvC0V40hzGEl30HPLp82e+kxr+Q0+g
+d82fvc4Yth5IPKINznp28GMs5/E9cUU3hMK4jFhKLMiOeIve3M/9ryHK874qpNjJ
+oSxxPz7+s2eqWoFc2px0KFIamTTLfi7Ju9aPb/AMlZNsUnbRsj7fQc7EJ8rwOnez
+w2Wy5VK4soX+qpuJ0Nm44ApzT8YmjYX/kAX0yQxgQuYbpcBWr9cOQjegu3FAqHqR
+h9ye7d8jQzCv34Wg/ar4rkqyQDcokuWAE7KQbnk51t7omzhM8eswFOAL1pas/8jW
+Bvy0VjYVU34P9aXxP8GiHQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQDCJoMLMIl8
+yvxrXH+kD2z163bwsMEIdsJxsXGjewmI/tDMyDLdYVQGJm9YRa/Oebylir7T+ayr
+NGj7b+Uo5KezgnRw9iQ9U8Xz6oKNxMNHB0mw5v7eR2cDFTzzNm1jYReIxWVryLOj
+al4C5uWqoIOHUNYibSJZIjNpzR/Zu4d/Ijt3+oJz9OFRXlaXYuDqLrm8hsUkxBm8
+s6GS79Dvw75M689ZKrKQs/15ceFYqx1hTvePW7kK5tuhW//Hf2IX4pwwtn5x0t4A
+M47qO71Zo3BxJFToNgALaw2+ixWNqy4kZ429NQjXArtq6eUI6IaOTU1ER2UAcOjN
+OOC5mBDmmMZa
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-single-alt-name.crt b/src/test/ssl/ssl/server-single-alt-name.crt
index 7affdd68e7..077a60a7ad 100644
--- a/src/test/ssl/ssl/server-single-alt-name.crt
+++ b/src/test/ssl/ssl/server-single-alt-name.crt
@@ -1,19 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDEjCCAfqgAwIBAgIIICEDAxQSBwIwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDVDCCAjygAwIBAgIIICMHExY1IwgwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTAzMDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMCAxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAMWKHC1lrog7A8ye8C3NM38JBiQBMuIZR40wORl0hJxj5Tp8
-dX8Xo2Thi9Ry33+YfMwfkkF66ZRwnMMEa8VYBmOz+fZFzF19WpE8F1CR3PxKE7ai
-zvunxy8oMxdXdIuTTzt8a5NcDLe22C4Yj21qaZVoh182ycvMH93V4MwsLcV3/GdV
-Ko7QpwP2ZCf5D1rhyccx+Trwyb2bKvhW5Jd3GrRacFJQFfUyrAu/FvyuSPmn86ab
-Jkr7CCgFlg6e4O9SFY7yXiOgLotsoQ5/YriTLinvUTGCMCSxaol97qx3I2gUpCZu
-i7H+4Dt9L5FcCMshl0TU32dsjw6El1Wbzp6voCsCAwEAAaMuMCwwKgYDVR0RBCMw
-IYIfc2luZ2xlLmFsdC1uYW1lLnBnLXNzbHRlc3QudGVzdDANBgkqhkiG9w0BAQsF
-AAOCAQEAUIhBQLzQgd7wHlT9DARxcC7SZwQtnk2BVqMYTRBU4uIa0i2HVyetpe1P
-rREthYq5sgaSqdonD9Splg8BLUlah9y3v9j6DBxkxNnz/3AZuA5oPaC/TZ+lwlX3
-QNWWFNaNZdcQbvjUvoPXIbJ6U9UDfByOJdoN4kJ6xe8Faj1Mp5Euqzr1ErrMtPWJ
-XLnXLV4WyAx+iMAbofXNlCyUorPGA8lRudzQ7bKdrhMZDE66VYwlwsUejEiODt7M
-NGTDs4aAZz9cBRjMeXhvX60cFQoykjAvWbieUKOgaFmJJyKemFj12cLeWyxvUodI
-kYtgAdzftiCSrbDjl1pzPSM6RC/E/A==
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowIDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAxYocLWWuiDsDzJ7wLc0zfwkGJAEy4hlHjTA5GXSEnGPl
+Onx1fxejZOGL1HLff5h8zB+SQXrplHCcwwRrxVgGY7P59kXMXX1akTwXUJHc/EoT
+tqLO+6fHLygzF1d0i5NPO3xrk1wMt7bYLhiPbWpplWiHXzbJy8wf3dXgzCwtxXf8
+Z1UqjtCnA/ZkJ/kPWuHJxzH5OvDJvZsq+Fbkl3catFpwUlAV9TKsC78W/K5I+afz
+ppsmSvsIKAWWDp7g71IVjvJeI6Aui2yhDn9iuJMuKe9RMYIwJLFqiX3urHcjaBSk
+Jm6Lsf7gO30vkVwIyyGXRNTfZ2yPDoSXVZvOnq+gKwIDAQABo24wbDAqBgNVHREE
+IzAhgh9zaW5nbGUuYWx0LW5hbWUucGctc3NsdGVzdC50ZXN0MB0GA1UdDgQWBBRE
+be2UnhcFV/bd5hEMML2w60NbbTAfBgNVHSMEGDAWgBTyjzpmQFBkSCLXLoL/Vp7C
+s+50CjANBgkqhkiG9w0BAQsFAAOCAQEA1pyC1Vb1EOgMdcdMq+u0FI+7GHGkEeg7
+qWMcLvu7mbcbcyzLriBUk1vKDYw+6WspTc6vvqMGxNVdwchm/93rUM/JI4C6nrmr
+3TJqE578C3EI+4YZxLLRnfYWBO0uyUfLkdjT3n0Tnu643wYYoKOgpZRV2WgfktK6
+KoRqWlkXkVoV/qZUS9O67XtNttvCFMrPiM4YbGmwQ7lUZ9qzojy4Fb0AWcZOVEIy
+2b7FMOUrIzk9CgTRtEqeobSD98p3OXGtzVZf2hY9vLgA1hnbVjmB2Kt3QMhnicvt
+/Z7o8o88cmcrs0PXMe90tt1JBssTFs6+ARCsgUkEwzCRnvVX+Yky9w==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server.crl b/src/test/ssl/ssl/server.crl
index 331a83cb62..7ed68e0220 100644
--- a/src/test/ssl/ssl/server.crl
+++ b/src/test/ssl/ssl/server.crl
@@ -1,11 +1,11 @@
-----BEGIN X509 CRL-----
-MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
-MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
-MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
-+10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
-4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
-ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
-imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
-B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+MIIBpzCBkDANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowGzAZAgggIwcTFjUjCxcNMjMwNzEz
+MTQzNTI0WjANBgkqhkiG9w0BAQsFAAOCAQEADIkF8oS84O2PJw/C9BAzgrkd+EsO
+QL6mXUGBgXwmujfpv0Z8YK91k4+xV9hQRMjWe/DkU01+gmFhYoDvAzweuNQzx8lZ
+bYKu0dGTEpTd+OG1LbxYmt4f5xh096R5iLo7c7e2kMHvfNG7VwvKQrPeMqh7AcKy
+Fukt8C0Xc7Tfv2l2toEQUAl5UDUKEAovN6iB0qycpvi0nboyiDo8mV0p1jlAn846
+EeXjwm8tyGXzTFq16ypPwnlBM9d5Ml/p5WTN69nDux18G+iSCr+UDzLDYvLF11p3
+lEqpSo5lQg9zYuOgMCvu3g5BtwJgORPSiW/yZ5BXUfWvPi0XRPrknxMByA==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/server_ca.crt b/src/test/ssl/ssl/server_ca.crt
index 0d6d7a6f82..8b010e7ca4 100644
--- a/src/test/ssl/ssl/server_ca.crt
+++ b/src/test/ssl/ssl/server_ca.crt
@@ -1,19 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
--
2.32.1 (Apple Git-133)
v5-0002-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patchapplication/octet-stream; name=v5-0002-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patch; x-unix-mode=0644Download
From e048c524e1da51d1cde5038e464c5bece7a41b06 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Thu, 13 Jul 2023 17:50:01 +0200
Subject: [PATCH v5 2/2] 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.
Author: Cary Huang <cary.huang@highgo.ca>
Discussion: https://postgr.es/m/182b8565486.10af1a86f158715.2387262617218380588@highgo.ca
---
contrib/sslinfo/Makefile | 2 +-
contrib/sslinfo/meson.build | 1 +
contrib/sslinfo/sslinfo--1.2--1.3.sql | 12 ++++
contrib/sslinfo/sslinfo.c | 67 +++++++++++++++++++++
contrib/sslinfo/sslinfo.control | 2 +-
doc/src/sgml/monitoring.sgml | 20 ++++++
doc/src/sgml/sslinfo.sgml | 30 +++++++++
src/backend/catalog/system_views.sql | 4 +-
src/backend/libpq/be-secure-openssl.c | 47 +++++++++++++++
src/backend/utils/activity/backend_status.c | 2 +
src/backend/utils/adt/pgstatfuncs.c | 46 ++++++++------
src/include/catalog/pg_proc.dat | 6 +-
src/include/libpq/libpq-be.h | 2 +
src/include/utils/backend_status.h | 2 +
src/test/regress/expected/rules.out | 12 ++--
src/test/ssl/t/001_ssltests.pl | 8 +--
src/test/ssl/t/003_sslinfo.pl | 14 +++++
17 files changed, 245 insertions(+), 32 deletions(-)
create mode 100644 contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..78a5a83d5c 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 999456d3a4..215b01daff 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..9d64d2bfa4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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 timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notbefore'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notafter() RETURNS timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..e4ecf78889 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#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 +35,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_timestamp(ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -225,6 +227,39 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into timestamp
+ *
+ * Parameter: time - OpenSSL ASN1_TIME structure.
+ *
+ * Returns Datum, which can be directly returned from a C language SQL
+ * function.
+ */
+static Datum
+ASN1_TIME_to_timestamp(ASN1_TIME * time)
+{
+ struct tm tm_time;
+ struct pg_tm pgtm_time;
+ Timestamp ts;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ pgtm_time.tm_sec = tm_time.tm_sec;
+ pgtm_time.tm_min = tm_time.tm_min;
+ pgtm_time.tm_hour = tm_time.tm_hour;
+ pgtm_time.tm_mday = tm_time.tm_mday;
+ pgtm_time.tm_mon = tm_time.tm_mon + 1;
+ pgtm_time.tm_year = tm_time.tm_year + 1900;
+
+ if (tm2timestamp(&pgtm_time, 0, NULL, &ts))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("failed to convert tm to timestamp")));
+
+ PG_RETURN_TIMESTAMP(ts);
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +517,35 @@ ssl_extension_info(PG_FUNCTION_ARGS)
/* All done */
SRF_RETURN_DONE(funcctx);
}
+
+/*
+ * Returns current client certificate notBefore timestamp in
+ * timestamp 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_timestamp(X509_get_notBefore(cert));
+}
+
+/*
+ * Returns current client certificate notAfter timestamp in
+ * timestamp 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_timestamp(X509_get_notAfter(cert));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 588b720f57..42c7808f50 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2257,6 +2257,26 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
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 UTC 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 UTC timestamp of the client certificate, or NULL if no client
+ certificate was supplied.
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..06f5728096 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -240,6 +240,36 @@ emailAddress
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notbefore() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notbefore</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not before</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notafter() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notafter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not after</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index af65af6bdd..f7c2cfb8cd 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -970,7 +970,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 658b09988d..4babb3d05f 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -36,6 +36,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 +73,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 Timestamp ASN1_TIME_to_timestamp(ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool SSL_initialized = false;
@@ -1406,6 +1408,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, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notBefore(port->peer));
+ else
+ *ptr = 0;
+}
+
+void
+be_tls_get_peer_not_after(Port *port, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notAfter(port->peer));
+ else
+ *ptr = 0;
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1549,6 +1569,33 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a cstring in format of YYYY-MM-DDThh:mm:ssZ.
+ */
+static Timestamp
+ASN1_TIME_to_timestamp(ASN1_TIME * time)
+{
+ struct tm tm_time;
+ struct pg_tm pgtm_time;
+ Timestamp ts;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ pgtm_time.tm_sec = tm_time.tm_sec;
+ pgtm_time.tm_min = tm_time.tm_min;
+ pgtm_time.tm_hour = tm_time.tm_hour;
+ pgtm_time.tm_mday = tm_time.tm_mday;
+ pgtm_time.tm_mon = tm_time.tm_mon + 1;
+ pgtm_time.tm_year = tm_time.tm_year + 1900;
+
+ if (tm2timestamp(&pgtm_time, 0, NULL, &ts))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("timestamp out of range")));
+
+ return ts;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 38f91a495b..02dc9d7931 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -367,6 +367,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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 2a4c8ef87f..9071981f98 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -303,7 +303,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);
@@ -395,7 +395,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
pfree(clipped_activity);
/* leader_pid */
- nulls[29] = true;
+ nulls[31] = true;
proc = BackendPidGetProc(beentry->st_procpid);
@@ -432,8 +432,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)
{
@@ -441,8 +441,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;
}
}
}
@@ -587,35 +587,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] = TimestampGetDatum(beentry->st_sslstatus->ssl_not_before);
+ else
+ nulls[25] = true;
+
+ if (beentry->st_sslstatus->ssl_not_after != 0)
+ values[26] = TimestampGetDatum(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
{
@@ -645,6 +655,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 6996073989..878c997e87 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5413,9 +5413,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,timestamp,timestamp,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 => '3318',
descr => 'statistics: information about progress of backends running maintenance command',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index a0b74c8095..02765ba9d9 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -298,6 +298,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, Timestamp *ptr);
+extern void be_tls_get_peer_not_after(Port *port, Timestamp *ptr);
/*
* Get the server certificate hash for SCRAM channel binding type
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 77939a0aed..1e4fedb661 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -61,6 +61,8 @@ typedef struct PgBackendSSLStatus
char ssl_client_serial[NAMEDATALEN];
char ssl_issuer_dn[NAMEDATALEN];
+ Timestamp ssl_not_before;
+ Timestamp ssl_not_after;
} PgBackendSSLStatus;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index e07afcd4aa..30108846c1 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1760,7 +1760,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,
@@ -1878,7 +1878,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,
@@ -2080,7 +2080,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,
@@ -2113,8 +2113,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 76442de063..bad41cacc8 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -543,8 +543,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.
@@ -745,8 +745,8 @@ command_like(
'-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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E\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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E,\Q2023-06-29 01:01:01\E,\Q2050-01-01 01:01:01\E\r?$}mx,
'pg_stat_ssl with client certificate');
# client key with wrong permissions
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 5306aad802..f050a6f4f9 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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 = '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 = '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';",
--
2.32.1 (Apple Git-133)
Hello
The way we typically ship extensions in contrib/ is to not create a new base
version .sql file for smaller changes like adding a few functions. For this
patch we should keep --1.2.sql and instead supply a 1.2--1.3.sql with the new
functions.
Thank you for pointing this out. It makes sense to me.
+ errmsg("failed to convert tm to timestamp")));
I think this error is too obscure for the user to act on, what we use elsewhere
is "timestamp out of range" and I think thats more helpful. I do wonder if
there is ever a legitimate case when this can fail while still having a
authenticated client connection?
My bad here, you are right. "timestamp out of range" is a much better error message. However, in an authenticated client connection, there should not be a legitimate case where the not before and not after can fall out of range. The "not before" and "not after" timestamps in a X509 certificate are normally represented by ASN1, which has maximum timestamp of December 31, 9999. The timestamp data structure in PostgreSQL on the other hand can support year up to June 3, 5874898. Assuming the X509 certificate is generated correctly and no data corruptions happening (which is unlikely), the conversion from ASN1 to timestamp shall not result in out of range error.
Perhaps calling "tm2timestamp(&pgtm_time, 0, NULL, &ts)" without checking the return code would be just fine. I see some other usages of tm2timstamp() in other code areas also skip checking the return code.
I have addressed the issues above in a new v5 patchset which includes a new
patch for setting stable validity on the test certificates (the notBefore time
was arbitrarily chosen to match the date of opening up the tree for v17 - we
just need a date in the past). Your two patches are rolled into a single one
with a commit message added to get started on that part as well.
thank you so much for addressing the ssl tests to make "not before" and "not after" timestamps static in the test certificate and also adjusting 003_sslinfo.pl to expect the new static timestamps in the v5 patches. I am able to apply both and all tests are passing. I did not know this test certificate could be changed by `cd src/test/ssl && make -f sslfiles.mk`, but now I know, thanks to you :p.
Best regards
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
On 14 Jul 2023, at 20:41, Cary Huang <cary.huang@highgo.ca> wrote:
Perhaps calling "tm2timestamp(&pgtm_time, 0, NULL, &ts)" without checking the return code would be just fine. I see some other usages of tm2timstamp() in other code areas also skip checking the return code.
I think we want to know about any failures, btu we can probably make it into an
elog() instead, as it should never fail.
--
Daniel Gustafsson
Hello
Perhaps calling "tm2timestamp(&pgtm_time, 0, NULL, &ts)" without checking the return code would be just fine. I see some other usages of tm2timstamp() in other code areas also skip checking the return code.
I think we want to know about any failures, btu we can probably make it into an
elog() instead, as it should never fail.
Yes, sure. I have corrected the error message to elog(ERROR, "timestamp out of range") on a rare tm2timestamp() failure. Please see the attached patch based on your v5. "v6-0001-Set-fixed-dates-for-test-certificates-validity.patch" is exactly the same as "v5-0001-Set-fixed-dates-for-test-certificates-validity.patch", I just up the version to be consistent.
thank you very much
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
Attachments:
v6-0001-Set-fixed-dates-for-test-certificates-validity.patchapplication/octet-stream; name=v6-0001-Set-fixed-dates-for-test-certificates-validity.patchDownload
From b1c76ef7fab37693f65c67bbb7be707e8c0e0285 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Thu, 13 Jul 2023 17:44:22 +0200
Subject: [PATCH v5 1/2] Set fixed dates for test certificates validity
Rather than specifying a validity of 10 000 days into the future
for test certificate generation, this hardcodes the notBefore and
notAfter attributes to set values. This will allow writing tests
which will not depend on when the certificates were generated. An
upcoming patch for adding notBefore and notAfter to pg_stat_ssl
and sslinfo requires this.
Discussion: https://postgr.es/m/182b8565486.10af1a86f158715.2387262617218380588@highgo.ca
---
src/test/ssl/conf/cas.config | 5 +-
src/test/ssl/ssl/both-cas-1.crt | 70 ++++++++++---------
src/test/ssl/ssl/both-cas-2.crt | 70 ++++++++++---------
src/test/ssl/ssl/client+client_ca.crt | 65 +++++++++--------
src/test/ssl/ssl/client-crldir/9bb9e3c3.r0 | 20 +++---
src/test/ssl/ssl/client-dn.crt | 32 ++++-----
src/test/ssl/ssl/client-long.crt | 34 ++++-----
src/test/ssl/ssl/client-revoked-utf8.crt | 30 ++++----
src/test/ssl/ssl/client-revoked.crt | 30 ++++----
src/test/ssl/ssl/client.crl | 20 +++---
src/test/ssl/ssl/client.crt | 30 ++++----
src/test/ssl/ssl/client_ca.crt | 35 +++++-----
src/test/ssl/ssl/client_ext.crt | 33 +++++----
.../ssl/ssl/root+client-crldir/9bb9e3c3.r0 | 20 +++---
src/test/ssl/ssl/root+client.crl | 20 +++---
src/test/ssl/ssl/root+client_ca.crt | 35 +++++-----
.../ssl/ssl/root+server-crldir/a836cc2d.r0 | 18 ++---
src/test/ssl/ssl/root+server.crl | 18 ++---
src/test/ssl/ssl/root+server_ca.crt | 35 +++++-----
src/test/ssl/ssl/server-cn-and-alt-names.crt | 36 +++++-----
.../ssl/ssl/server-cn-and-ip-alt-names.crt | 35 +++++-----
src/test/ssl/ssl/server-cn-only+server_ca.crt | 67 +++++++++---------
src/test/ssl/ssl/server-cn-only.crt | 32 ++++-----
src/test/ssl/ssl/server-crldir/a836cc2d.r0 | 18 ++---
src/test/ssl/ssl/server-ip-alt-names.crt | 33 ++++-----
.../ssl/ssl/server-ip-cn-and-alt-names.crt | 34 ++++-----
.../ssl/server-ip-cn-and-dns-alt-names.crt | 35 +++++-----
src/test/ssl/ssl/server-ip-cn-only.crt | 30 ++++----
src/test/ssl/ssl/server-ip-in-dnsname.crt | 32 +++++----
.../ssl/ssl/server-multiple-alt-names.crt | 36 +++++-----
src/test/ssl/ssl/server-no-names.crt | 30 ++++----
src/test/ssl/ssl/server-revoked.crt | 32 ++++-----
src/test/ssl/ssl/server-single-alt-name.crt | 33 ++++-----
src/test/ssl/ssl/server.crl | 18 ++---
src/test/ssl/ssl/server_ca.crt | 35 +++++-----
35 files changed, 600 insertions(+), 556 deletions(-)
diff --git a/src/test/ssl/conf/cas.config b/src/test/ssl/conf/cas.config
index 2c4851033a..43bcf739bb 100644
--- a/src/test/ssl/conf/cas.config
+++ b/src/test/ssl/conf/cas.config
@@ -38,7 +38,10 @@ crl = ./ssl/server.crl
dir = ./ssl/
database = ./ssl/client_ca-certindex
default_md = sha256
-default_days= 10000
+# Startdate and enddate are required for testing notBefore/notAfter with
+# stable timestamps.
+default_startdate = 20230629010101Z
+default_enddate = 20500101010101Z
default_crl_days= 10000
certificate = ./ssl/client_ca.crt
private_key = ./ssl/client_ca.key
diff --git a/src/test/ssl/ssl/both-cas-1.crt b/src/test/ssl/ssl/both-cas-1.crt
index 4f4bc707d6..1584b4ba0e 100644
--- a/src/test/ssl/ssl/both-cas-1.crt
+++ b/src/test/ssl/ssl/both-cas-1.crt
@@ -18,40 +18,46 @@ OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/both-cas-2.crt b/src/test/ssl/ssl/both-cas-2.crt
index 01d0c4d6a4..674d8e6a7e 100644
--- a/src/test/ssl/ssl/both-cas-2.crt
+++ b/src/test/ssl/ssl/both-cas-2.crt
@@ -18,40 +18,46 @@ OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client+client_ca.crt b/src/test/ssl/ssl/client+client_ca.crt
index 7fafa14de1..fe7719e14b 100644
--- a/src/test/ssl/ssl/client+client_ca.crt
+++ b/src/test/ssl/ssl/client+client_ca.crt
@@ -1,37 +1,40 @@
-----BEGIN CERTIFICATE-----
-MIIC0zCCAbsCCCAhAwMUEgcAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC1TCCAb0CCCAjBxMWNSQAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAWMRQwEgYDVQQD
-DAtzc2x0ZXN0dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALSL
-oC6h8sBABL8kWRjFQJHZNcwmuRRWjzhBYR4gDKcBThCBIuEr5PZEkkXnJniXKHct
-bCzaBarUwG+bWGg6BiFWX3PP5MZvLG7ExP9yTrDjdwjKozkJCNWSow0hdYLaxkpm
-rYI6rDJ5T1CZBRLD4RYOjU39WVIxYkHlhJYtH0Cdv5PuzCOEtLdKQySSVq6heJen
-koLvK7AaF1x8uDiwM+o9t69pORWbOh/6aCCPeYmvhPIRvEqyZjGvPJ2kXau4R1vN
-NmepRIZ0VjQ/rQxo7dGWk38cfgsTeFI4G26DiYn08pFR47swUdfiMyx3MaGQiz9X
-I2nUqjM+W84iUxrR82MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEACSZo32raJHcB
-rYHeomzynmzgMVBHSA4XsXZVQw4+zBUER+/ZdQbtw6F/qdeWRvTl8TJjwoydta7u
-4gUkgAnQhYm2f8XEBe/+MUegH+y54Yk6rtmkdLxJLGKZ0IUfYkn20sg/NZrltbog
-A8glWRGVD8cEOaxUaNSQ4Xqmqsqjd6Kh8snVfIIcWgKgnTNgyapM5ePBpS2IREhN
-u9fjikQQf6F/dycsm22OP7aWsp1XPs3nqnoq9ZnhQrITMwsGcjbU7+v8La2GbiJV
-8yAy136NSXUujIG/8eqhICWZPqj+KbdVZupOsUeVoeuSwLXJjm4GWY0xH92emqCI
-ac+HriJv5w==
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMBYxFDASBgNV
+BAMMC3NzbHRlc3R1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+tIugLqHywEAEvyRZGMVAkdk1zCa5FFaPOEFhHiAMpwFOEIEi4Svk9kSSRecmeJco
+dy1sLNoFqtTAb5tYaDoGIVZfc8/kxm8sbsTE/3JOsON3CMqjOQkI1ZKjDSF1gtrG
+SmatgjqsMnlPUJkFEsPhFg6NTf1ZUjFiQeWEli0fQJ2/k+7MI4S0t0pDJJJWrqF4
+l6eSgu8rsBoXXHy4OLAz6j23r2k5FZs6H/poII95ia+E8hG8SrJmMa88naRdq7hH
+W802Z6lEhnRWND+tDGjt0ZaTfxx+CxN4UjgbboOJifTykVHjuzBR1+IzLHcxoZCL
+P1cjadSqMz5bziJTGtHzYwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAQnfs7UO2g
+iilUgCQAfa9Vb0ZSivD7ryjnLsdwYRLIlb0YceME9qtSv2UYBfS9KpwG7+jONMQB
+kvbe611/TaF0T7EC1GIWuTMs8jknJ2bgPbS8D8jiFWTci+SDDog4EVoakSLoirW6
+yB4398upjtanAdnjoNpE4REXPDHzDm2Dico2RCObJh1VAEK+q6gLJxQtGvdPyG3L
+Fhjs7ky1lsxIvHlts8c1e4vhnVpxdS3I5r6N38qFXEJnc1tv/e+TH50mdrZlzRHF
+TPgnZzWCGTHmT5YT3yoAldWG4uWzMsB+2eY/crRefM9byc0omjCxDTrk9nA6JWsf
+0c6pBc6aKzdi
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0 b/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0
index f75eb1c0bc..202f9f44d0 100644
--- a/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0
+++ b/src/test/ssl/ssl/client-crldir/9bb9e3c3.r0
@@ -1,12 +1,12 @@
-----BEGIN X509 CRL-----
-MIIBwDCBqTANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMjA3
-MTgyMjI4MTVaFw00OTEyMDMyMjI4MTVaMDYwGQIIICEDAxQSBwEXDTIyMDcxODIy
-MjgxNVowGQIIICIHGBUoFQAXDTIyMDcxODIyMjgxNVowDQYJKoZIhvcNAQELBQAD
-ggEBAFDH3m9AHpDjkEFjO6svnLJ2bTliGeKZaJW8/RAN4mWvWDhXDQfzqGcFHN2a
-SIL57Xc4PdwTiXuU4QEP4RvWW90LYKdcrcT8uh0AN3i7ShMwcV7I7owzF5+CBuT7
-Ev0MU4QIz0PjXoybXP6b3wHhZbEjYTLYdnYdqjrsAchUpyDQn6fiC0C7FgjCi4HL
-rNm2kMchFpzd6K9e41kxWVp7xCPXgqUK8OrxlW56ObkX8UpBIZzyU6RisJKOZJAn
-/+lwT43yTtU739atdXdSMvGHT9Y7LsrSDz9zgp2/iMTmfctnPcp81J/6jQZEP8kx
-OyPyZz4xy/EShWy+KUklfOoKRo8=
+MIIBwjCBqzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNjAZAgggIwcTFjUkAhcNMjMwNzEz
+MTQzNTI0WjAZAgggIwcTFjUkBRcNMjMwNzEzMTQzNTI0WjANBgkqhkiG9w0BAQsF
+AAOCAQEAl2jqLuwUgUTtzIKdLyAqIGf+zG0jfJXD9KFIsPeR+zfYWyNVzlWav68e
+zcLLhr9NWzHCXo0F5yiWVIO9pe2OF980Ez/24fTd6NPk3qG9AzLeLQ0jPhEgLaDw
+KFSTuaTbEuAUBGHMTjdoe6aOGsypUOXxse/G5enyx93yCC7boFkrYscfnQT2kFZT
+60Bhfr/4qkFdGJbp9ZIsTP8us4sktEDFn24Tq5f8sW7JyqIU83LRhjkIc8NALGCE
+DE7FgaGVUyuH8jYkVw4XLMwYo9gAy95pBxrDFq/r0Zm4E1rIEr8x7Ji7smUcubrb
+/MXu7OCXst4uzoRxFQctnP19AYIKZQ==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/client-dn.crt b/src/test/ssl/ssl/client-dn.crt
index 0db14e5977..3f5c80580c 100644
--- a/src/test/ssl/ssl/client-dn.crt
+++ b/src/test/ssl/ssl/client-dn.crt
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDDTCCAfUCCCAhBikTA0IAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDDzCCAfcCCCAjBxMWNSQBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjEwNjI5MjAwMzQyWhcNNDgxMTE0MjAwMzQyWjBQMQ0wCwYDVQQK
-DARQR0RHMRQwEgYDVQQLDAtFbmdpbmVlcmluZzEQMA4GA1UECwwHVGVzdGluZzEX
-MBUGA1UEAwwOc3NsdGVzdHVzZXItZG4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDES64qtkofPjeG4VbUVKfzABLC0CurvxqLTEpokq/St9WAWDrzc8PJ
-YireEZp4ec5rHVyQVvHqzzaZFAMvbRUQgMdGKG4Vgkn8l96KxHa4Q6yxYoQOts10
-AuvU9LuGKT0lxndMggHDmREUOAkFYKp7IeypseUGkJ6sWs+DlTwK1hST+EUAU/5f
-q/pAngJ+oar20m8WNxaAhJUKtBBecdRdqYy/h3Ab43iPhj+N9IFXiSV9EWhteBae
-L/TEE+s7/4L74xwvJe2EiVETo3lMy2aVJ4/4pOMq7U+Gr/0wxk0jqRrOahAE6pOI
-cQFBFsOkyUaC4dzqtjeSrsw5igQbJC19AgMBAAEwDQYJKoZIhvcNAQELBQADggEB
-AECbQQ9rBzCexNI3VKDVA+CZa0ib48XbcJwXmva3spvjjCB5cGPToyF1B+4mVg1H
-1uM/XRAoQmNRtB+xKEAceMSxJA02tBlwMOclXlO0oGLYyc+S61K+UEPSk6Kka4aC
-NpeLSqN5ahC9z8C5uMJl36pFf13aU05uRkXKcI4gkn02I4jRc/a8gF7URdhdf920
-KmYSUh1V0B3pPAB6ArqJ60iHOqkCYIIIbi2EpVP53IKkoB9tr4ud8oMoN6ggIXU1
-2oHvnaKJ7RZaQNefS3WweyHxr4cCVtEour/ELph48OuW6Y5jqPT+5Ln3Qz0e6KW9
-o3thBx0aKSYlmt9gH254M9M=
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMFAxDTALBgNV
+BAoMBFBHREcxFDASBgNVBAsMC0VuZ2luZWVyaW5nMRAwDgYDVQQLDAdUZXN0aW5n
+MRcwFQYDVQQDDA5zc2x0ZXN0dXNlci1kbjCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMRLriq2Sh8+N4bhVtRUp/MAEsLQK6u/GotMSmiSr9K31YBYOvNz
+w8liKt4Rmnh5zmsdXJBW8erPNpkUAy9tFRCAx0YobhWCSfyX3orEdrhDrLFihA62
+zXQC69T0u4YpPSXGd0yCAcOZERQ4CQVgqnsh7Kmx5QaQnqxaz4OVPArWFJP4RQBT
+/l+r+kCeAn6hqvbSbxY3FoCElQq0EF5x1F2pjL+HcBvjeI+GP430gVeJJX0RaG14
+Fp4v9MQT6zv/gvvjHC8l7YSJUROjeUzLZpUnj/ik4yrtT4av/TDGTSOpGs5qEATq
+k4hxAUEWw6TJRoLh3Oq2N5KuzDmKBBskLX0CAwEAATANBgkqhkiG9w0BAQsFAAOC
+AQEAYi8MtTEYoqqxjoy/QOYuuWIryNwvpHh9ty8q+r8gWPuySMaIb+qfWh7qK1OY
+ng9HUXdXn+kpZIy6GMVtVSprPn5J3gLCZMsXqHxh5XtHf8DkSwmaQrVSFmu0Wkri
+txnNl4OHwMIGbX0o6oN7rNdlgYxLyMtPzO+KfygjO4HX8Hm5Jz0DM2K3airnFkCc
+IwYdMmaEMykRRl2W5wpSgHjYrReL3qopdWj97sKTY4H3ZuBR7i2V9ni6/mJFUD2u
+8tLeUTB1vOhRk6JhtRagNIQHg7tsUX6Fx3QkdosGjSCWPePzv4UC4GYvEjbOvsxv
+hIPtSVIjtS8eN6co3XJP+dTd4w==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-long.crt b/src/test/ssl/ssl/client-long.crt
index a1db55b5c3..2fec398e17 100644
--- a/src/test/ssl/ssl/client-long.crt
+++ b/src/test/ssl/ssl/client-long.crt
@@ -1,20 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDWjCCAkICCCAiBRIUREYAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDXDCCAkQCCCAjBxMWNSQEMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjIwNTEyMjE0NDQ3WhcNNDkwOTI3MjE0NDQ3WjCBnDEsMCoGA1UE
-CgwjUG9zdGdyZVNRTCBHbG9iYWwgRGV2ZWxvcG1lbnQgR3JvdXAxITAfBgNVBAsM
-GFNvbWUgT3JnYW5pemF0aW9uYWwgVW5pdDFJMEcGA1UEAwxAc3NsLTEyMzQ1Njc4
-OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2
-Nzg5MDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgxmeHiVRuBTwlG
-Q1oM2M1ckQCI/o4hYcO9BYdxDYHiA7jy1WVenyj8BtUi5Aj9VDhpfiuewDarGQ5a
-TggD1pMjkw0MorBKBr9+1u1xGH/8Q3lkgU+OQXrPglo4IrVcqaoZFQ0nuMaVbieX
-0dDyTfsTaVQYYtqAtzhI/UGSIOhk2+lB9fP68jw9cLH0QYvR+qQ0IPG13I5zmSYP
-Mj0VYwMn9TF9/2sBOSRVgTVAcrYgOQLk3s/fGe66tmVBIWYcq65ygqD1+weu+Pax
-jPnwsefkdnf6JdYRG1F1Co7g52poPEYieAHfQOJ69sG0LYx0lBODC69qvSJ4WdCQ
-0zKw288CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEArr5r1UxgUzPykmu5ZdL6y8TA
-ZbSQ1yBY0nhsRwRkDd66iPK9U6T6K2+pL8Vc6ioov9WOtHQ6ohP3gSavd40cHRmF
-auwIsZ4Wk0mjftpOuPFp1hyo8d/QYrbEm3qNe5qln5S9h8ipoYvFtf5zlK2KHJFz
-9ehZMZ1zGAERNCVM8UUQKyUuZB5GyrZlbslf6P/9Bsc54YUWxP2pr5r/RJ6DeXfI
-zAFfXT8AFVlClARA949gpX0LVrXryDN60CUJ88QJmYCQ3AtIgzYYeqcdYHTd8eS2
-9P5whDdU5NvROP+LjETeReJF4Bfyc2gM7zxZD2BDSf5exvnNqiy42/lR1b4szw==
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMIGcMSwwKgYD
+VQQKDCNQb3N0Z3JlU1FMIEdsb2JhbCBEZXZlbG9wbWVudCBHcm91cDEhMB8GA1UE
+CwwYU29tZSBPcmdhbml6YXRpb25hbCBVbml0MUkwRwYDVQQDDEBzc2wtMTIzNDU2
+Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0
+NTY3ODkwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2DGZ4eJVG4FP
+CUZDWgzYzVyRAIj+jiFhw70Fh3ENgeIDuPLVZV6fKPwG1SLkCP1UOGl+K57ANqsZ
+DlpOCAPWkyOTDQyisEoGv37W7XEYf/xDeWSBT45Bes+CWjgitVypqhkVDSe4xpVu
+J5fR0PJN+xNpVBhi2oC3OEj9QZIg6GTb6UH18/ryPD1wsfRBi9H6pDQg8bXcjnOZ
+Jg8yPRVjAyf1MX3/awE5JFWBNUBytiA5AuTez98Z7rq2ZUEhZhyrrnKCoPX7B674
+9rGM+fCx5+R2d/ol1hEbUXUKjuDnamg8RiJ4Ad9A4nr2wbQtjHSUE4MLr2q9InhZ
+0JDTMrDbzwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCUIOBu5ea3vSVpiqCGMphv
+V26dDpEl1OMpvPIM5Ss1sp9ogOdBg7ahkDE51J0QaB3yN6mci3sN6yi77U3zXXUv
+qI0hdR3nwjTLJSpW2p6ONW43PKPhKr42UdBH5iRVlNY7rto2x3xC0iuzvPAJjIJJ
+OJMZYl/A43O8XZW68m9Z5kH3Vi/l0wtjElfnjqI0DAuQEL/TQTzK9qTIhdAqMAKG
+deTGSqpz+ID2CfuN+TBV2NAseilZ4JC0xZxaJpoqmK3yTtgKBhJ3vQN//fc1TdPy
+9+zvnSRIJZJque58ZKnqbMq3c3RRSo0eOZn7FZopcIRsn5hzDeIVTJcBJ68jcxrL
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-revoked-utf8.crt b/src/test/ssl/ssl/client-revoked-utf8.crt
index de471d1e60..4189c75de8 100644
--- a/src/test/ssl/ssl/client-revoked-utf8.crt
+++ b/src/test/ssl/ssl/client-revoked-utf8.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC2DCCAcACCCAiBxgVKBUAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC2jCCAcICCCAjBxMWNSQFMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjIwNzE4MjIyODE1WhcNNDkxMjAzMjIyODE1WjAbMRkwFwYDVQQD
-DBDOn860z4XPg8+Dzq3Osc+CMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAvBiL1mVjTrzZ6sbrvfu746dzh+EEyuJNkCwPeJTtpva2wqqRUMYw05cV5kzi
-YQ3UikMP5Yz0FXTeWoahSpJAWeR5XsFx3wOQvRzwi1KWm2CHr/rb7KbPvoZQdXuV
-8UeKrQ6PrEvjoarHAUZuWyUC6EnEAGuiKl5yuax5mkTcK5F8pig2/SS/UonX5ar5
-58rOUEaIdyZmXtrO86cm5S5Oz3G2naQB3PPPOhtkoGBHikRHiqBPVRpX3w9TIpBL
-BZbT4MIZ+fCjZ9wXj4aiDUzPglu6/Tfx9sNcxc6Ilz/XHfPuBVyyjgrny2SrW0W4
-KlhU09y+m5gKL358z8tj599DowIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAE47ns
-wfceztieaRQtoF+gPcCuImOJqaB7jTE6cQ+aoW/q+sUlOh7AD0IZqhS4o0A4O+ny
-MD7kHkpYP+ctHNomsSQRkFTDZ2ZJGcRgxbwMOSvsKcgNOTMGqpXQiP0x0m7QMBGl
-EHeu5MqG/IK/ZlH9aOTvSnHegB6ztct/7wXMeFCflsWLp6wvnv9YpddaaXf95Oms
-9kwbVYkI1wxaBsAO8VGbJw1YtdErgd65qKTJa45xndtm61i1Jeig5asSNQPwjfZ5
-aNHZ9GsSwsc31Q/6iiezbPwgdAi3ih//uB2hznkMhObnqzR3n8Sw9zgL7DdFr2y9
-2R7kJuGq6DvlWFYS
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMBsxGTAXBgNV
+BAMMEM6fzrTPhc+Dz4POrc6xz4IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC8GIvWZWNOvNnqxuu9+7vjp3OH4QTK4k2QLA94lO2m9rbCqpFQxjDTlxXm
+TOJhDdSKQw/ljPQVdN5ahqFKkkBZ5HlewXHfA5C9HPCLUpabYIev+tvsps++hlB1
+e5XxR4qtDo+sS+OhqscBRm5bJQLoScQAa6IqXnK5rHmaRNwrkXymKDb9JL9Sidfl
+qvnnys5QRoh3JmZe2s7zpyblLk7PcbadpAHc8886G2SgYEeKREeKoE9VGlffD1Mi
+kEsFltPgwhn58KNn3BePhqINTM+CW7r9N/H2w1zFzoiXP9cd8+4FXLKOCufLZKtb
+RbgqWFTT3L6bmAovfnzPy2Pn30OjAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAASZ
+M/4tx9qm7G9TEKHHg/Da7GOrGWnYwluWcO/jnIN4jCPyxwj6EmxZGEBKqFUhj3kY
+hwL+249Y2YABOLqu9x/YJz1KtZUgkwTGh6yfT5xOSOCXij7ukpge1gXtodYtnBgP
+FmJOdFygrXxWex3vr+F2Fnh93Isxd/nFof/Rwmi4JTJr6JjalyGuvNDGZc/N16/u
+uR3AE0zGLfM093GbJe9E9j44DGMbNlwHvZ2NXojX34kNoRttonPHmXGKWSCyufUc
+uG+STq5T/DFnr06Ugj2TPCMyEgDEA4unzP5uxAijXVRSkyOrAtZrFtzbab/wjTLt
+0AGeljtaei/bMAh11Cs=
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client-revoked.crt b/src/test/ssl/ssl/client-revoked.crt
index 51ebe924a6..2cc0c933cd 100644
--- a/src/test/ssl/ssl/client-revoked.crt
+++ b/src/test/ssl/ssl/client-revoked.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC0zCCAbsCCCAhAwMUEgcBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC1TCCAb0CCCAjBxMWNSQCMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAWMRQwEgYDVQQD
-DAtzc2x0ZXN0dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKAX
-JmNmfqmvpVAeWEmJxi7feku2sZKA7yMyyZMCboBqsNVO9gOpQFE8gD1Z7bJm4aDK
-QxByuspYPFOBwty9YW4UqRa4kyEyd08x+PsHQx9SmWJTNpNIH6yq5LCcme37QMrg
-b8wUZRWwXsaKUfVUI6oALjSgcibMJXTntCsD9J5m/07U/ZZALe1460rreTFHsxVZ
-708Wm5u7UHIgxvvEKhNG/JR9zd1Tl1mVgnlz0a8G6Dt22gJnLnuFdtDdACwET/kG
-TRJQWuyavpe+1TY53kZNO442hOzwhlZVnz4IKaWaLNQMtbG9iYStEvaWa8p0E/3J
-N6oRuELiqXJp/wW3v/MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAcVhPcu55HcSf
-Mci38T/fOBaiDUvzWwG/XlQRzFxcS+ZY/vYMbgor6PliGlCFBF4Mca2qtTs7zXRz
-8aLNVX53p98Cnnn97mW4aYNbNdM87R76IqJdj40brEolu1JNOyFJRYzoaebABf9r
-R64FTt3YVM9qjJrHG/apYwKwgAMxVzZ/M+3ujahP/8mOYD/Utj+lYHnXJmuHAYE6
-EnTxTSb2J+IsK8KuPoGjUPNZRW8zIUE0luMpJahvtmFVW91Vue7dW0AOmHpjmGUB
-J9Vwxe7KJRW5/4dz6kMD2pKY3D9sBgXeku/QDVz/hdyB5YT0WChFiZn20DZyhOtu
-moHgw8OJzg==
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMBYxFDASBgNV
+BAMMC3NzbHRlc3R1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+oBcmY2Z+qa+lUB5YSYnGLt96S7axkoDvIzLJkwJugGqw1U72A6lAUTyAPVntsmbh
+oMpDEHK6ylg8U4HC3L1hbhSpFriTITJ3TzH4+wdDH1KZYlM2k0gfrKrksJyZ7ftA
+yuBvzBRlFbBexopR9VQjqgAuNKByJswldOe0KwP0nmb/TtT9lkAt7XjrSut5MUez
+FVnvTxabm7tQciDG+8QqE0b8lH3N3VOXWZWCeXPRrwboO3baAmcue4V20N0ALARP
++QZNElBa7Jq+l77VNjneRk07jjaE7PCGVlWfPggppZos1Ay1sb2JhK0S9pZrynQT
+/ck3qhG4QuKpcmn/Bbe/8wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAtVsoTdoLZ
+2PMVSDIEc3VRhjNS5+EuYcW+7h0se/7IpBauHoZhn+JD8YVtE04yz2YkglrnChmJ
+iL8xc+f1PbQatxpU7HnSswn3JevC+jZWnGvAxqR2oR3cAioF7sK1vnYLnd2OPqcy
+P9T+tzi90fiVOVOlrm00hjJBNcDIhofjY9td3wogA1SO8vXQteZ1gXNt0nzmfuNZ
+vZvspk+A/vN8tbR6BTagUxPRxajiT0xoIJFD6Qx2ZPglgffJKDwQQ3kvYr7dLMgO
++TDcLL8GK2MAxglgOqvUlRwfwl0ZXu3ZsGjim8pF+dPJB1dUCm9KbG2sIscPNLUe
+9p2w5FZaNk7p
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client.crl b/src/test/ssl/ssl/client.crl
index f75eb1c0bc..202f9f44d0 100644
--- a/src/test/ssl/ssl/client.crl
+++ b/src/test/ssl/ssl/client.crl
@@ -1,12 +1,12 @@
-----BEGIN X509 CRL-----
-MIIBwDCBqTANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMjA3
-MTgyMjI4MTVaFw00OTEyMDMyMjI4MTVaMDYwGQIIICEDAxQSBwEXDTIyMDcxODIy
-MjgxNVowGQIIICIHGBUoFQAXDTIyMDcxODIyMjgxNVowDQYJKoZIhvcNAQELBQAD
-ggEBAFDH3m9AHpDjkEFjO6svnLJ2bTliGeKZaJW8/RAN4mWvWDhXDQfzqGcFHN2a
-SIL57Xc4PdwTiXuU4QEP4RvWW90LYKdcrcT8uh0AN3i7ShMwcV7I7owzF5+CBuT7
-Ev0MU4QIz0PjXoybXP6b3wHhZbEjYTLYdnYdqjrsAchUpyDQn6fiC0C7FgjCi4HL
-rNm2kMchFpzd6K9e41kxWVp7xCPXgqUK8OrxlW56ObkX8UpBIZzyU6RisJKOZJAn
-/+lwT43yTtU739atdXdSMvGHT9Y7LsrSDz9zgp2/iMTmfctnPcp81J/6jQZEP8kx
-OyPyZz4xy/EShWy+KUklfOoKRo8=
+MIIBwjCBqzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNjAZAgggIwcTFjUkAhcNMjMwNzEz
+MTQzNTI0WjAZAgggIwcTFjUkBRcNMjMwNzEzMTQzNTI0WjANBgkqhkiG9w0BAQsF
+AAOCAQEAl2jqLuwUgUTtzIKdLyAqIGf+zG0jfJXD9KFIsPeR+zfYWyNVzlWav68e
+zcLLhr9NWzHCXo0F5yiWVIO9pe2OF980Ez/24fTd6NPk3qG9AzLeLQ0jPhEgLaDw
+KFSTuaTbEuAUBGHMTjdoe6aOGsypUOXxse/G5enyx93yCC7boFkrYscfnQT2kFZT
+60Bhfr/4qkFdGJbp9ZIsTP8us4sktEDFn24Tq5f8sW7JyqIU83LRhjkIc8NALGCE
+DE7FgaGVUyuH8jYkVw4XLMwYo9gAy95pBxrDFq/r0Zm4E1rIEr8x7Ji7smUcubrb
+/MXu7OCXst4uzoRxFQctnP19AYIKZQ==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/client.crt b/src/test/ssl/ssl/client.crt
index 1f6ae05fe4..eaf8830192 100644
--- a/src/test/ssl/ssl/client.crt
+++ b/src/test/ssl/ssl/client.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC0zCCAbsCCCAhAwMUEgcAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC1TCCAb0CCCAjBxMWNSQAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAWMRQwEgYDVQQD
-DAtzc2x0ZXN0dXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALSL
-oC6h8sBABL8kWRjFQJHZNcwmuRRWjzhBYR4gDKcBThCBIuEr5PZEkkXnJniXKHct
-bCzaBarUwG+bWGg6BiFWX3PP5MZvLG7ExP9yTrDjdwjKozkJCNWSow0hdYLaxkpm
-rYI6rDJ5T1CZBRLD4RYOjU39WVIxYkHlhJYtH0Cdv5PuzCOEtLdKQySSVq6heJen
-koLvK7AaF1x8uDiwM+o9t69pORWbOh/6aCCPeYmvhPIRvEqyZjGvPJ2kXau4R1vN
-NmepRIZ0VjQ/rQxo7dGWk38cfgsTeFI4G26DiYn08pFR47swUdfiMyx3MaGQiz9X
-I2nUqjM+W84iUxrR82MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEACSZo32raJHcB
-rYHeomzynmzgMVBHSA4XsXZVQw4+zBUER+/ZdQbtw6F/qdeWRvTl8TJjwoydta7u
-4gUkgAnQhYm2f8XEBe/+MUegH+y54Yk6rtmkdLxJLGKZ0IUfYkn20sg/NZrltbog
-A8glWRGVD8cEOaxUaNSQ4Xqmqsqjd6Kh8snVfIIcWgKgnTNgyapM5ePBpS2IREhN
-u9fjikQQf6F/dycsm22OP7aWsp1XPs3nqnoq9ZnhQrITMwsGcjbU7+v8La2GbiJV
-8yAy136NSXUujIG/8eqhICWZPqj+KbdVZupOsUeVoeuSwLXJjm4GWY0xH92emqCI
-ac+HriJv5w==
+Y2VydHMwIBcNMjMwNjI5MDEwMTAxWhgPMjA1MDAxMDEwMTAxMDFaMBYxFDASBgNV
+BAMMC3NzbHRlc3R1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+tIugLqHywEAEvyRZGMVAkdk1zCa5FFaPOEFhHiAMpwFOEIEi4Svk9kSSRecmeJco
+dy1sLNoFqtTAb5tYaDoGIVZfc8/kxm8sbsTE/3JOsON3CMqjOQkI1ZKjDSF1gtrG
+SmatgjqsMnlPUJkFEsPhFg6NTf1ZUjFiQeWEli0fQJ2/k+7MI4S0t0pDJJJWrqF4
+l6eSgu8rsBoXXHy4OLAz6j23r2k5FZs6H/poII95ia+E8hG8SrJmMa88naRdq7hH
+W802Z6lEhnRWND+tDGjt0ZaTfxx+CxN4UjgbboOJifTykVHjuzBR1+IzLHcxoZCL
+P1cjadSqMz5bziJTGtHzYwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAQnfs7UO2g
+iilUgCQAfa9Vb0ZSivD7ryjnLsdwYRLIlb0YceME9qtSv2UYBfS9KpwG7+jONMQB
+kvbe611/TaF0T7EC1GIWuTMs8jknJ2bgPbS8D8jiFWTci+SDDog4EVoakSLoirW6
+yB4398upjtanAdnjoNpE4REXPDHzDm2Dico2RCObJh1VAEK+q6gLJxQtGvdPyG3L
+Fhjs7ky1lsxIvHlts8c1e4vhnVpxdS3I5r6N38qFXEJnc1tv/e+TH50mdrZlzRHF
+TPgnZzWCGTHmT5YT3yoAldWG4uWzMsB+2eY/crRefM9byc0omjCxDTrk9nA6JWsf
+0c6pBc6aKzdi
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client_ca.crt b/src/test/ssl/ssl/client_ca.crt
index ef48749f76..31867bd0f4 100644
--- a/src/test/ssl/ssl/client_ca.crt
+++ b/src/test/ssl/ssl/client_ca.crt
@@ -1,19 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/client_ext.crt b/src/test/ssl/ssl/client_ext.crt
index 9874ce49b9..5204391e46 100644
--- a/src/test/ssl/ssl/client_ext.crt
+++ b/src/test/ssl/ssl/client_ext.crt
@@ -1,21 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDezCCAmOgAwIBAgIIICEREAQyQQAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDQTCCAimgAwIBAgIIICMHExY1JAMwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IGNs
-aWVudCBjZXJ0czAeFw0yMTExMTAwMzMyNDFaFw00OTAzMjgwMzMyNDFaMBYxFDAS
-BgNVBAMMC3NzbHRlc3R1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEArCHikkEQLFITbn3ZfO8X2RW3fELeaImgy8W4Pkkc4LxdHCWjdCML/vtE/ZVu
-Op74qrQQWT0HKXFVUiZLbjAgV2PONS6VFHhc3sTFxuTaBnVdY+K98hoFnXskINt/
-wgwUhRcRZuKPcZvEHiqF6e3g3lQa99l1nVKPGPLOCvVhSgoV0Gwgxok0t7s25BCV
-ZmpMAwSTxpeviLF0e2MsttuyClQ4nuD92EHZX3BuG0WNPLxiwikV96uMffpMRGsx
-uiAHzD5ykYM7/b3eU0bjfi0J0qcfTSeytqFuRCNEukJpmtUmyYGqsFJ7HN7ejCY7
-ObAlBn8h+4bgwBRaeZDZLTMaYQIDAQABo4GgMIGdMAwGA1UdEwEB/wQCMAAwEwYD
+aWVudCBjZXJ0czAgFw0yMzA2MjkwMTAxMDFaGA8yMDUwMDEwMTAxMDEwMVowFjEU
+MBIGA1UEAwwLc3NsdGVzdHVzZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCsIeKSQRAsUhNufdl87xfZFbd8Qt5oiaDLxbg+SRzgvF0cJaN0Iwv++0T9
+lW46nviqtBBZPQcpcVVSJktuMCBXY841LpUUeFzexMXG5NoGdV1j4r3yGgWdeyQg
+23/CDBSFFxFm4o9xm8QeKoXp7eDeVBr32XWdUo8Y8s4K9WFKChXQbCDGiTS3uzbk
+EJVmakwDBJPGl6+IsXR7Yyy227IKVDie4P3YQdlfcG4bRY08vGLCKRX3q4x9+kxE
+azG6IAfMPnKRgzv9vd5TRuN+LQnSpx9NJ7K2oW5EI0S6Qmma1SbJgaqwUnsc3t6M
+Jjs5sCUGfyH7huDAFFp5kNktMxphAgMBAAGjZTBjMAwGA1UdEwEB/wQCMAAwEwYD
VR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFPPv1n7k1Vd9BBC4eoGWPZwVz2Lx
-MFkGA1UdIwRSMFChRKRCMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBmb3IgUG9z
-dGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlggggIQMDFBIHATANBgkq
-hkiG9w0BAQsFAAOCAQEAtqIeTmUhtHyCt5k2yx88F0dKshYq4Z+LQI+agyZ1fRE6
-Ux5p+SBGbzvc+NcUvc7yGG6w2G/nTVnGwSHN9NtQa2T2XbHJysJ/dwCfmRsachKz
-4kCp0zAHEDrEmZua0sy5BLwwVCk5WNBR0lZ35WmIEuRA+5G/2lCywtrb9W4YnbAM
-nH7BtZE8qPbK4OicB40I2NXz6KhG3755oKN03VC1IaX9JFQxf37ac7jVK5bsjfaF
-0xCAeuDN6wDiVHZj6q1GhhmNLzaF5zmU2e/cI1nTI5tfGKnygavlZIz2VvAlcypt
-YZdMDy69VbTWUa57UPCspghgvm5M2/Hjmz50CXGMvw==
+MB8GA1UdIwQYMBaAFJ+k69LJmd6wA7AwNCKBYRVLva02MA0GCSqGSIb3DQEBCwUA
+A4IBAQBsDUu6W6jXfgOkBGhZpwTtpThQ3fizEmBLXiy479Sa27YzdXCrLkql+XDv
+Z0nh8t7gvSw5ZCl9eZ13yg9etAfGCkNtkI37EVh4rMMqP3NkjBT2qwdG+pfwcF/c
++vrSK3H47lVIE5AShJJAwlU0Thf1bfyjzTnoGxEj2+YBMMhAykp9XbAgtM14hCQV
+07niaMv4kmmHDoUU72UH7GYnfnsCkUKhbisw7qOojd4MPX/kvU77+S3UURHJKKHy
+Rag+GP03NeF+d1z3niVBOIXE6hzlfaxB0w0SW7fXgQFYRBujTUYdcSZ5ZuT9kHyH
+9zHx+isaomV7U7yIQ9mGT/fDugki
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0 b/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0
index f75eb1c0bc..202f9f44d0 100644
--- a/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0
+++ b/src/test/ssl/ssl/root+client-crldir/9bb9e3c3.r0
@@ -1,12 +1,12 @@
-----BEGIN X509 CRL-----
-MIIBwDCBqTANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMjA3
-MTgyMjI4MTVaFw00OTEyMDMyMjI4MTVaMDYwGQIIICEDAxQSBwEXDTIyMDcxODIy
-MjgxNVowGQIIICIHGBUoFQAXDTIyMDcxODIyMjgxNVowDQYJKoZIhvcNAQELBQAD
-ggEBAFDH3m9AHpDjkEFjO6svnLJ2bTliGeKZaJW8/RAN4mWvWDhXDQfzqGcFHN2a
-SIL57Xc4PdwTiXuU4QEP4RvWW90LYKdcrcT8uh0AN3i7ShMwcV7I7owzF5+CBuT7
-Ev0MU4QIz0PjXoybXP6b3wHhZbEjYTLYdnYdqjrsAchUpyDQn6fiC0C7FgjCi4HL
-rNm2kMchFpzd6K9e41kxWVp7xCPXgqUK8OrxlW56ObkX8UpBIZzyU6RisJKOZJAn
-/+lwT43yTtU739atdXdSMvGHT9Y7LsrSDz9zgp2/iMTmfctnPcp81J/6jQZEP8kx
-OyPyZz4xy/EShWy+KUklfOoKRo8=
+MIIBwjCBqzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNjAZAgggIwcTFjUkAhcNMjMwNzEz
+MTQzNTI0WjAZAgggIwcTFjUkBRcNMjMwNzEzMTQzNTI0WjANBgkqhkiG9w0BAQsF
+AAOCAQEAl2jqLuwUgUTtzIKdLyAqIGf+zG0jfJXD9KFIsPeR+zfYWyNVzlWav68e
+zcLLhr9NWzHCXo0F5yiWVIO9pe2OF980Ez/24fTd6NPk3qG9AzLeLQ0jPhEgLaDw
+KFSTuaTbEuAUBGHMTjdoe6aOGsypUOXxse/G5enyx93yCC7boFkrYscfnQT2kFZT
+60Bhfr/4qkFdGJbp9ZIsTP8us4sktEDFn24Tq5f8sW7JyqIU83LRhjkIc8NALGCE
+DE7FgaGVUyuH8jYkVw4XLMwYo9gAy95pBxrDFq/r0Zm4E1rIEr8x7Ji7smUcubrb
+/MXu7OCXst4uzoRxFQctnP19AYIKZQ==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+client.crl b/src/test/ssl/ssl/root+client.crl
index 459f48da43..2e0616905c 100644
--- a/src/test/ssl/ssl/root+client.crl
+++ b/src/test/ssl/ssl/root+client.crl
@@ -10,14 +10,14 @@ SBNr2rpYp7Coc3GeCoWPcClgSrABD3Z5GY1YAdLGiXVKaH3CmdJTznhEPagE4z5R
+GrJP3XxJ1OC
-----END X509 CRL-----
-----BEGIN X509 CRL-----
-MIIBwDCBqTANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMjA3
-MTgyMjI4MTVaFw00OTEyMDMyMjI4MTVaMDYwGQIIICEDAxQSBwEXDTIyMDcxODIy
-MjgxNVowGQIIICIHGBUoFQAXDTIyMDcxODIyMjgxNVowDQYJKoZIhvcNAQELBQAD
-ggEBAFDH3m9AHpDjkEFjO6svnLJ2bTliGeKZaJW8/RAN4mWvWDhXDQfzqGcFHN2a
-SIL57Xc4PdwTiXuU4QEP4RvWW90LYKdcrcT8uh0AN3i7ShMwcV7I7owzF5+CBuT7
-Ev0MU4QIz0PjXoybXP6b3wHhZbEjYTLYdnYdqjrsAchUpyDQn6fiC0C7FgjCi4HL
-rNm2kMchFpzd6K9e41kxWVp7xCPXgqUK8OrxlW56ObkX8UpBIZzyU6RisJKOZJAn
-/+lwT43yTtU739atdXdSMvGHT9Y7LsrSDz9zgp2/iMTmfctnPcp81J/6jQZEP8kx
-OyPyZz4xy/EShWy+KUklfOoKRo8=
+MIIBwjCBqzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNjAZAgggIwcTFjUkAhcNMjMwNzEz
+MTQzNTI0WjAZAgggIwcTFjUkBRcNMjMwNzEzMTQzNTI0WjANBgkqhkiG9w0BAQsF
+AAOCAQEAl2jqLuwUgUTtzIKdLyAqIGf+zG0jfJXD9KFIsPeR+zfYWyNVzlWav68e
+zcLLhr9NWzHCXo0F5yiWVIO9pe2OF980Ez/24fTd6NPk3qG9AzLeLQ0jPhEgLaDw
+KFSTuaTbEuAUBGHMTjdoe6aOGsypUOXxse/G5enyx93yCC7boFkrYscfnQT2kFZT
+60Bhfr/4qkFdGJbp9ZIsTP8us4sktEDFn24Tq5f8sW7JyqIU83LRhjkIc8NALGCE
+DE7FgaGVUyuH8jYkVw4XLMwYo9gAy95pBxrDFq/r0Zm4E1rIEr8x7Ji7smUcubrb
+/MXu7OCXst4uzoRxFQctnP19AYIKZQ==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+client_ca.crt b/src/test/ssl/ssl/root+client_ca.crt
index 7819c54828..ff8281fba0 100644
--- a/src/test/ssl/ssl/root+client_ca.crt
+++ b/src/test/ssl/ssl/root+client_ca.crt
@@ -18,21 +18,24 @@ OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-Y2xpZW50IGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+ce
-8rkNfoCvI9Wjug9pxsptsdjhZ4s7ZZ8eD5VlloryK2JccusQIX61XY8I3OZjLTgq
-1SpZbHQvktRH6gmU7tfoBdEnRuXB7idkbYOKIrC0hdttb/5rDzjQGtXTmwoVrCcJ
-nvO1Whay/gdsoqX1tT1MTPWu/6dfQkQXA0PizVvmBasAEQchxqtcH2rSc6TPE13v
-lxJ0X1vSlz92uT6kenrxUDs43AH/kASdIQBHXVA4XWBAm7NRqwKX7BBwbsF2m3Qh
-+NY9Bf9MnJHLcnVnwZdlW5nd7H7BTB43XvkiYascqusYki+fY58eGSprZ/VUjmGx
-pgQnQXWCu0U3JyUL/QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQC1syY2Rk02m5PGtfkMUIU7ZSe0mM+g0BgWAyCF/mFFYdfY0xHtqy0x
-QWkW9OR0KBl4JpphDDolHoNL3TLydH3t4inX8SAOpaUdsjMcIPKqjT1htQm0Pk5r
-vFYvKuVrxMnV0F+wMmZRuziKWrZlVDwBMfCAchzuVexDWfcjTmUQmhZxJuUzORw3
-swgh9HIpxjMkgdlHodbMAEpMIkkoeJnph3I9uTocXZbK/lAInggQdm0Q+on1ZT0A
-ljO/6jisDZzIguE4ZAQ2DfYsGI8H3tz/+76uIwwBNOmu0woUDSWXVcPWiviq49Bi
-GmH0KlUfWAphj86IfTWXT1HRay3eZQt3
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBjbGllbnQgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7
+5x7yuQ1+gK8j1aO6D2nGym2x2OFniztlnx4PlWWWivIrYlxy6xAhfrVdjwjc5mMt
+OCrVKllsdC+S1EfqCZTu1+gF0SdG5cHuJ2Rtg4oisLSF221v/msPONAa1dObChWs
+Jwme87VaFrL+B2yipfW1PUxM9a7/p19CRBcDQ+LNW+YFqwARByHGq1wfatJzpM8T
+Xe+XEnRfW9KXP3a5PqR6evFQOzjcAf+QBJ0hAEddUDhdYECbs1GrApfsEHBuwXab
+dCH41j0F/0yckctydWfBl2Vbmd3sfsFMHjde+SJhqxyq6xiSL59jnx4ZKmtn9VSO
+YbGmBCdBdYK7RTcnJQv9AgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQUn6Tr0smZ3rADsDA0IoFhFUu9rTYwZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQAbYUfwGvV4u5Gpbhv5yxdueC0faKVIEXYRnT4Dky01cV7pGkFSFndlA2mFsj1g
+uuzkTFPMedcBefMoq2o2eX2B4ogrFHovxELI82i9pbv/MmsGNYwbMsp2lnUhNWon
+QwxFqMGA5Y2p8vyEG7lrHKiFDdt7uPxcOeTiWo0ZpC8uThqiR4fUkPinQ3EHEFGQ
++zl+G3pb4VRUzsyqh2n9swudqQcwjsDlQlkQ2vzVb6IWWiUCwL3V7HGPGmlVbsFG
+nQ1M44aBtWbBQtubfBRwYb5r+4sRN94LST6Phmhnd/AJccIKdCaheq+yLVVGiCJN
+3nDTmgTVSSmOm/RRmSXNp7AH
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0 b/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0
index 331a83cb62..7ed68e0220 100644
--- a/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0
+++ b/src/test/ssl/ssl/root+server-crldir/a836cc2d.r0
@@ -1,11 +1,11 @@
-----BEGIN X509 CRL-----
-MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
-MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
-MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
-+10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
-4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
-ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
-imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
-B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+MIIBpzCBkDANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowGzAZAgggIwcTFjUjCxcNMjMwNzEz
+MTQzNTI0WjANBgkqhkiG9w0BAQsFAAOCAQEADIkF8oS84O2PJw/C9BAzgrkd+EsO
+QL6mXUGBgXwmujfpv0Z8YK91k4+xV9hQRMjWe/DkU01+gmFhYoDvAzweuNQzx8lZ
+bYKu0dGTEpTd+OG1LbxYmt4f5xh096R5iLo7c7e2kMHvfNG7VwvKQrPeMqh7AcKy
+Fukt8C0Xc7Tfv2l2toEQUAl5UDUKEAovN6iB0qycpvi0nboyiDo8mV0p1jlAn846
+EeXjwm8tyGXzTFq16ypPwnlBM9d5Ml/p5WTN69nDux18G+iSCr+UDzLDYvLF11p3
+lEqpSo5lQg9zYuOgMCvu3g5BtwJgORPSiW/yZ5BXUfWvPi0XRPrknxMByA==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+server.crl b/src/test/ssl/ssl/root+server.crl
index 8b0c716d63..93ffa5986e 100644
--- a/src/test/ssl/ssl/root+server.crl
+++ b/src/test/ssl/ssl/root+server.crl
@@ -10,13 +10,13 @@ SBNr2rpYp7Coc3GeCoWPcClgSrABD3Z5GY1YAdLGiXVKaH3CmdJTznhEPagE4z5R
+GrJP3XxJ1OC
-----END X509 CRL-----
-----BEGIN X509 CRL-----
-MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
-MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
-MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
-+10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
-4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
-ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
-imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
-B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+MIIBpzCBkDANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowGzAZAgggIwcTFjUjCxcNMjMwNzEz
+MTQzNTI0WjANBgkqhkiG9w0BAQsFAAOCAQEADIkF8oS84O2PJw/C9BAzgrkd+EsO
+QL6mXUGBgXwmujfpv0Z8YK91k4+xV9hQRMjWe/DkU01+gmFhYoDvAzweuNQzx8lZ
+bYKu0dGTEpTd+OG1LbxYmt4f5xh096R5iLo7c7e2kMHvfNG7VwvKQrPeMqh7AcKy
+Fukt8C0Xc7Tfv2l2toEQUAl5UDUKEAovN6iB0qycpvi0nboyiDo8mV0p1jlAn846
+EeXjwm8tyGXzTFq16ypPwnlBM9d5Ml/p5WTN69nDux18G+iSCr+UDzLDYvLF11p3
+lEqpSo5lQg9zYuOgMCvu3g5BtwJgORPSiW/yZ5BXUfWvPi0XRPrknxMByA==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/root+server_ca.crt b/src/test/ssl/ssl/root+server_ca.crt
index 5074f4fa9b..a094886e0f 100644
--- a/src/test/ssl/ssl/root+server_ca.crt
+++ b/src/test/ssl/ssl/root+server_ca.crt
@@ -18,21 +18,24 @@ OCZhKLxVZiZmO71BBwsTgwtU58/G9e2ciGGdltI8ANlmVfdtwgRz3b7H9EUZat6s
kubl/m5HWBsKJEWEzFWrWkQV3ipoTmorJ6KCGABBCeVYmg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-and-alt-names.crt b/src/test/ssl/ssl/server-cn-and-alt-names.crt
index 12d1ec363e..982c02a514 100644
--- a/src/test/ssl/ssl/server-cn-and-alt-names.crt
+++ b/src/test/ssl/ssl/server-cn-and-alt-names.crt
@@ -1,20 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIDVTCCAj2gAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDmTCCAoGgAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTAzMDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMEYxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5h
-bWUucGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAwVES+mD1iY1UBGWNLsuBxGkyOGTI1X/sXcCUZ7aLOGkXHYatiUTcIrSNNAS5
-yCvbq/A/C1NuDw59nrU2TitcLBx5AIhz74EV+xv/u/GuX0gvJzDWh/6EeMzDIcJL
-Iq7iEgO8ff5fuAzuwuNguZkX51JjBiXc2rtfgPI3CMU1lqCbb2vW9ZN4Pm7wRqvd
-d/F/mySiFmLFsB4HLhCGZN89vO4cbslN4+YrGKEcHeXGWRaxv6gSXbpEgUYpefzz
-+QB7AepU5aWntm3X+E1we5AHLSKckwUdBuT5uYgmZcYA/kCC4/9RS02jTlu4Vfrd
-SemHwuo2UQ5ODJxzAhWrEl3F4QIDAQABo0swSTBHBgNVHREEQDA+gh1kbnMxLmFs
-dC1uYW1lLnBnLXNzbHRlc3QudGVzdIIdZG5zMi5hbHQtbmFtZS5wZy1zc2x0ZXN0
-LnRlc3QwDQYJKoZIhvcNAQELBQADggEBAG3dFQ/DqjFbjzIOni079R3I94lAZqbc
-cRUumDPSzihKwvCCnU5quqnYkOFISqBZsYmxR5fiHx4wT+jmWvLSltkaeS6gcGC1
-zuO8GFzL+PATUX63js8IfE3WYJE/bjmDVVzJOBArrbsExofdE2F2kkkLkjhk0ylg
-/TrAKtyqpsob0b4ZjMloR5JFHQXGHN/922x6Do1vduHMXlGckmR0sX6Mg/fiChVh
-vixUJje4W9ohft8G7lj3GnzI1gHEMp2PYKM+wqOug/gXEQuMIFlhjp2Mc6bAvFsD
-grgdAgcYUvgKukF9efJHq2V5XjqBWrmGAOQkiH1y+9gxhiHUiw+vojY=
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjNaGA8yMDUwMTEyODE0MzUyM1owRjEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMSQwIgYDVQQDDBtjb21tb24t
+bmFtZS5wZy1zc2x0ZXN0LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDBURL6YPWJjVQEZY0uy4HEaTI4ZMjVf+xdwJRntos4aRcdhq2JRNwitI00
+BLnIK9ur8D8LU24PDn2etTZOK1wsHHkAiHPvgRX7G/+78a5fSC8nMNaH/oR4zMMh
+wksiruISA7x9/l+4DO7C42C5mRfnUmMGJdzau1+A8jcIxTWWoJtva9b1k3g+bvBG
+q9138X+bJKIWYsWwHgcuEIZk3z287hxuyU3j5isYoRwd5cZZFrG/qBJdukSBRil5
+/PP5AHsB6lTlpae2bdf4TXB7kActIpyTBR0G5Pm5iCZlxgD+QILj/1FLTaNOW7hV
++t1J6YfC6jZRDk4MnHMCFasSXcXhAgMBAAGjgYwwgYkwRwYDVR0RBEAwPoIdZG5z
+MS5hbHQtbmFtZS5wZy1zc2x0ZXN0LnRlc3SCHWRuczIuYWx0LW5hbWUucGctc3Ns
+dGVzdC50ZXN0MB0GA1UdDgQWBBQnWI8n7O4aU6PooSwyIepyrEpsajAfBgNVHSME
+GDAWgBTyjzpmQFBkSCLXLoL/Vp7Cs+50CjANBgkqhkiG9w0BAQsFAAOCAQEAQk/M
+emDTPYUx/JrSdTyvVDeBaUMUjWQ78LO1j/2RqtBXh/tSnTvalOeuwBPqmz9+7HYR
+H2gYQNq4W1Y6SgTdbpEivEXPvp1XyQXtLMpwDGO4rKq3QOCOPX2zZLDPrRqGSev3
+jN7oV8C3yVUyhhSxu+BZo4lZ55soiehCjHNKR5xfcbR/AtshLullVNNqoGQQyalS
+9TNUKp7FqF52tIELvFMINoSf5aaLU1g7snxnVRbTFyne/oqeqFjW932M/vaFgAH7
+H8mfoJeAiG5GqVBKtf3kcakfBl1wjFCzpguvDd9Xi2AP1y3cPEotwFiKhCYMmGiA
+EnzrdmAeNGKb2w3wlA==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt b/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt
index 4e58c85ccb..fea2703aaf 100644
--- a/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt
+++ b/src/test/ssl/ssl/server-cn-and-ip-alt-names.crt
@@ -1,20 +1,21 @@
-----BEGIN CERTIFICATE-----
-MIIDLzCCAhegAwIBAgIIICERKRE1UQAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDcTCCAlmgAwIBAgIIICMHExY1IwEwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTExMjkxOTM1NTFaFw00OTA0MTYxOTM1NTFaMEYxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5h
-bWUucGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEA6+8IYKAFnZ7V+fDo1cyMpbGBLzCfJOQ/1o2jOGP4+GjpsZgv6S6UT2MheC8M
-iiEFrYwdsSIZyYc3jEZrluy/UuR0bCGtqU92BCqa0iBLhvHOgjR588u253eLxQtQ
-8iJn11QPrKMk35nMkmY8GfHt4sGFbvBL6+GpipHq7a6cde3Z+v4kCB5dKMYDUDtm
-3mJmviuGNAu5wOqItk2Yi5dwJs1054007KNH0Il43urxiOfnkLS0cG5kehboPf86
-vxBt3iHByrU/9/DY5IvQCfSXVNa6rb5w5/pGja9aCei6Mv1jQY/V8SMQTga+MOsA
-0WB9akxMi2NxwS2+BQ4k/McPlwIDAQABoyUwIzAhBgNVHREEGjAYhwTAAAIBhxAg
-AQ24AAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQAQLo2RzC07dG9p+J3A
-W6C0p3Y+Os/YE2D9wfp4TIDTZxcRUQZ0S6ahF1N6sp8l9KHBJHPU1cUpRAU1oD+Y
-SqmnP/VJRRDTTj9Ytdc/Vuo2jeLpSYhVKrCqtjqIrCwYJFoYRmMoxTtJGlwA0hSd
-kwo3XYrALPUQWUErTYPvNfDNIuUwqUXNfS0CXuIOVN3LJ+shegg6Pwbh9B5T9NHx
-kH+HswajhdpdnZIgh0FYTlTCPILDrB49aOWwqLa54AUA6WXa35hPsP8SoqL9Eucq
-ifPhBYyadsjOb+70N8GbbAsDPN1jCX9L8RuNcEkxSCKCYx91cWXh7K5KMPuGlzB7
-j8xB
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjNaGA8yMDUwMTEyODE0MzUyM1owRjEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMSQwIgYDVQQDDBtjb21tb24t
+bmFtZS5wZy1zc2x0ZXN0LnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDr7whgoAWdntX58OjVzIylsYEvMJ8k5D/WjaM4Y/j4aOmxmC/pLpRPYyF4
+LwyKIQWtjB2xIhnJhzeMRmuW7L9S5HRsIa2pT3YEKprSIEuG8c6CNHnzy7bnd4vF
+C1DyImfXVA+soyTfmcySZjwZ8e3iwYVu8Evr4amKkertrpx17dn6/iQIHl0oxgNQ
+O2beYma+K4Y0C7nA6oi2TZiLl3AmzXTnjTTso0fQiXje6vGI5+eQtLRwbmR6Fug9
+/zq/EG3eIcHKtT/38Njki9AJ9JdU1rqtvnDn+kaNr1oJ6Loy/WNBj9XxIxBOBr4w
+6wDRYH1qTEyLY3HBLb4FDiT8xw+XAgMBAAGjZTBjMCEGA1UdEQQaMBiHBMAAAgGH
+ECABDbgAAAAAAAAAAAAAAAEwHQYDVR0OBBYEFG+mujVw0u9XhfSYVs8/XJPwFCmF
+MB8GA1UdIwQYMBaAFPKPOmZAUGRIItcugv9WnsKz7nQKMA0GCSqGSIb3DQEBCwUA
+A4IBAQAm0M+VY4eZwfu47OPdiIJ4YxyGtcRCDDCuqZ8ACG7YH51Trhvm7SuHhGVQ
+aJvphWDPrt4e0Exmga0T8RJ2Xd49F9u21/biz+vvzdjpzcr3yd9YGQ2IoU35b3ln
+AVVB36i38eAOxYpSsv4CN01ilJYxhMdUQqRYjlagIYIp7dBwuQ7+uXUesBY6xgL/
+N0G+cUQuax8mokVB0HfNccbroXpJaz3fU1TSPiDgin7yMGkm9bTwj30pbesBOTID
+MqdYNodA7RIZslnmHn7q1rsGIBVUHrxUyH7/4m9ZbhI1Zz0VkoWAPklkqCO7moIb
+/oB/DmtwTndVB0urbGnEDzaoCntL
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-only+server_ca.crt b/src/test/ssl/ssl/server-cn-only+server_ca.crt
index 9870e8c17a..71ede03546 100644
--- a/src/test/ssl/ssl/server-cn-only+server_ca.crt
+++ b/src/test/ssl/ssl/server-cn-only+server_ca.crt
@@ -1,38 +1,41 @@
-----BEGIN CERTIFICATE-----
-MIIDAzCCAesCCCAhAwMUEgcBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDBTCCAe0CCCAjBxMWNSMCMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBGMR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxJDAiBgNVBAMMG2NvbW1vbi1uYW1lLnBn
-LXNzbHRlc3QudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWz
-VPMk7i5f+W0eEadRE+TTAtsIK08CkLMUnjs7zJkxnnm6RGBXPx6vK3AkAIi+wG4Y
-mXjYP3GuMiXaLjnWh2kzBSfIRQyNbTThnhSu3nDjAVkPexsSrPyiKimFuNgDfkGe
-5dQKa9Ag2SuVU4vd9SYxOMAiIFIC4ts4MLWWJf5D/PehdSuc0e5Me+91Nnbz90nl
-ds4lHvuDR+aKnZlTHmch3wfhXv7lNQImIBzfwl36Kd/bWB0fAEVFse3iZWmigaI/
-9FKh//WIq43TNLxn68OCQoyMe/HGjZDR/Xwo3rE6jg6/iAwSWib9yabfYPKbqq2G
-oFy6aYmmEquaDgLuX7kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA2AZrD9cTQXTW
-4j2tT8N/TTc6WK2ncN4h22NTte6vK7MVwsZJCtw5ndYkmxcWkXAqiclzWyMdayds
-WOa12CEH7jKAhivF4Hcw3oO3JHM5BA6KzLWBVz9uZksOM6mPqn29DTKvA/Y1V8tj
-mxK/KUA68h/u6inu3mo4ywBpb/tqHxxg2cjyR0faCmM0pwRM0HBr/16fUMfO83nj
-QG8g9J/bybu5sYso/aSoC5nUNp4XjmDMdVLdqg/nTe/ejS8IfFr0WQxBlqooqFgx
-MSE+kX2e2fHsuOWSU/9eClt6FpQrwoC2C8F+/4g1Uz7Liqc4yMHPwjgeP9ewrrLO
-iIhlNNPqpQ==
+Y2VydHMwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEYxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5hbWUu
+cGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+1bNU8yTuLl/5bR4Rp1ET5NMC2wgrTwKQsxSeOzvMmTGeebpEYFc/Hq8rcCQAiL7A
+bhiZeNg/ca4yJdouOdaHaTMFJ8hFDI1tNOGeFK7ecOMBWQ97GxKs/KIqKYW42AN+
+QZ7l1Apr0CDZK5VTi931JjE4wCIgUgLi2zgwtZYl/kP896F1K5zR7kx773U2dvP3
+SeV2ziUe+4NH5oqdmVMeZyHfB+Fe/uU1AiYgHN/CXfop39tYHR8ARUWx7eJlaaKB
+oj/0UqH/9YirjdM0vGfrw4JCjIx78caNkNH9fCjesTqODr+IDBJaJv3Jpt9g8puq
+rYagXLppiaYSq5oOAu5fuQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCT3LdsDzwy
+oKaXNuOgtENp4Pp4hLDXeZsepemYss75xfPsXyni9gWVTPIwwzq7NMawtP5q7zzB
+zUMiDgsL9J3d1kDcL0qbJV7xciwCA5D0O1EFKSogJK9jgdupswQZKNrEtM2F68mN
+SJ2aCJtIX/4lZb9KyRli4PDECrFjJM4vDQa9y05O5YY7lohvY5jubAAgexLT/n5r
+oycpw3xNzwGIQ8dAtjvtgONFFKAogWomFaCjWSBPW3ZVz4NM7CryH6oyxkUv/v+q
+/7vUykX0qBn7Vnk3nvVsqrqRRCbYXMz8qgMLeeXi5JjSeWDpYoiblIEfpf3FdtqS
+FnIQVHtAuZHb
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-cn-only.crt b/src/test/ssl/ssl/server-cn-only.crt
index acdf6f1a75..6429529226 100644
--- a/src/test/ssl/ssl/server-cn-only.crt
+++ b/src/test/ssl/ssl/server-cn-only.crt
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDAzCCAesCCCAhAwMUEgcBMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDBTCCAe0CCCAjBxMWNSMCMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBGMR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxJDAiBgNVBAMMG2NvbW1vbi1uYW1lLnBn
-LXNzbHRlc3QudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWz
-VPMk7i5f+W0eEadRE+TTAtsIK08CkLMUnjs7zJkxnnm6RGBXPx6vK3AkAIi+wG4Y
-mXjYP3GuMiXaLjnWh2kzBSfIRQyNbTThnhSu3nDjAVkPexsSrPyiKimFuNgDfkGe
-5dQKa9Ag2SuVU4vd9SYxOMAiIFIC4ts4MLWWJf5D/PehdSuc0e5Me+91Nnbz90nl
-ds4lHvuDR+aKnZlTHmch3wfhXv7lNQImIBzfwl36Kd/bWB0fAEVFse3iZWmigaI/
-9FKh//WIq43TNLxn68OCQoyMe/HGjZDR/Xwo3rE6jg6/iAwSWib9yabfYPKbqq2G
-oFy6aYmmEquaDgLuX7kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA2AZrD9cTQXTW
-4j2tT8N/TTc6WK2ncN4h22NTte6vK7MVwsZJCtw5ndYkmxcWkXAqiclzWyMdayds
-WOa12CEH7jKAhivF4Hcw3oO3JHM5BA6KzLWBVz9uZksOM6mPqn29DTKvA/Y1V8tj
-mxK/KUA68h/u6inu3mo4ywBpb/tqHxxg2cjyR0faCmM0pwRM0HBr/16fUMfO83nj
-QG8g9J/bybu5sYso/aSoC5nUNp4XjmDMdVLdqg/nTe/ejS8IfFr0WQxBlqooqFgx
-MSE+kX2e2fHsuOWSU/9eClt6FpQrwoC2C8F+/4g1Uz7Liqc4yMHPwjgeP9ewrrLO
-iIhlNNPqpQ==
+Y2VydHMwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEYxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5hbWUu
+cGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+1bNU8yTuLl/5bR4Rp1ET5NMC2wgrTwKQsxSeOzvMmTGeebpEYFc/Hq8rcCQAiL7A
+bhiZeNg/ca4yJdouOdaHaTMFJ8hFDI1tNOGeFK7ecOMBWQ97GxKs/KIqKYW42AN+
+QZ7l1Apr0CDZK5VTi931JjE4wCIgUgLi2zgwtZYl/kP896F1K5zR7kx773U2dvP3
+SeV2ziUe+4NH5oqdmVMeZyHfB+Fe/uU1AiYgHN/CXfop39tYHR8ARUWx7eJlaaKB
+oj/0UqH/9YirjdM0vGfrw4JCjIx78caNkNH9fCjesTqODr+IDBJaJv3Jpt9g8puq
+rYagXLppiaYSq5oOAu5fuQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCT3LdsDzwy
+oKaXNuOgtENp4Pp4hLDXeZsepemYss75xfPsXyni9gWVTPIwwzq7NMawtP5q7zzB
+zUMiDgsL9J3d1kDcL0qbJV7xciwCA5D0O1EFKSogJK9jgdupswQZKNrEtM2F68mN
+SJ2aCJtIX/4lZb9KyRli4PDECrFjJM4vDQa9y05O5YY7lohvY5jubAAgexLT/n5r
+oycpw3xNzwGIQ8dAtjvtgONFFKAogWomFaCjWSBPW3ZVz4NM7CryH6oyxkUv/v+q
+/7vUykX0qBn7Vnk3nvVsqrqRRCbYXMz8qgMLeeXi5JjSeWDpYoiblIEfpf3FdtqS
+FnIQVHtAuZHb
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-crldir/a836cc2d.r0 b/src/test/ssl/ssl/server-crldir/a836cc2d.r0
index 331a83cb62..7ed68e0220 100644
--- a/src/test/ssl/ssl/server-crldir/a836cc2d.r0
+++ b/src/test/ssl/ssl/server-crldir/a836cc2d.r0
@@ -1,11 +1,11 @@
-----BEGIN X509 CRL-----
-MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
-MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
-MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
-+10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
-4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
-ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
-imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
-B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+MIIBpzCBkDANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowGzAZAgggIwcTFjUjCxcNMjMwNzEz
+MTQzNTI0WjANBgkqhkiG9w0BAQsFAAOCAQEADIkF8oS84O2PJw/C9BAzgrkd+EsO
+QL6mXUGBgXwmujfpv0Z8YK91k4+xV9hQRMjWe/DkU01+gmFhYoDvAzweuNQzx8lZ
+bYKu0dGTEpTd+OG1LbxYmt4f5xh096R5iLo7c7e2kMHvfNG7VwvKQrPeMqh7AcKy
+Fukt8C0Xc7Tfv2l2toEQUAl5UDUKEAovN6iB0qycpvi0nboyiDo8mV0p1jlAn846
+EeXjwm8tyGXzTFq16ypPwnlBM9d5Ml/p5WTN69nDux18G+iSCr+UDzLDYvLF11p3
+lEqpSo5lQg9zYuOgMCvu3g5BtwJgORPSiW/yZ5BXUfWvPi0XRPrknxMByA==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/server-ip-alt-names.crt b/src/test/ssl/ssl/server-ip-alt-names.crt
index 8a1bc620bb..3f15775a34 100644
--- a/src/test/ssl/ssl/server-ip-alt-names.crt
+++ b/src/test/ssl/ssl/server-ip-alt-names.crt
@@ -1,19 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDCTCCAfGgAwIBAgIIICERKREEUAAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDSzCCAjOgAwIBAgIIICMHExY1IwMwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTExMjkxOTA0NTBaFw00OTA0MTYxOTA0NTBaMCAxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAOM8yB6aVWb17ujr3ayU62mxHQoqn4CvG9yXlJvGOGv/ursW
-Vs0UYJdc96LsNZN1szdm9ayNzCIw3eja+ULsjxCi6+3LM4pO76IORL/XFamlTPYb
-BZ4pHdZVB0nnZAAnWCZPyXdnjOKQ5+8unVXkfibkjj8UELBJ2snehsOa+CTkOBez
-zxYMqxAgbywLIYsW448brun7UXpWmqbGK+SsdGaIZ5Sb7Zezc5lt6CrLemTZTHHK
-7l4WZFCCEi4t3sgO8o1vDELD/IE5G8lyXvIdgJg6t8ssper7iCw6S8x+okhjiSjT
-vDLU2g4AanqZRZB49aPwTo0QUcJA2BCJxL9xLy8CAwEAAaMlMCMwIQYDVR0RBBow
-GIcEwAACAYcQIAENuAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAwZJ+
-8KpABTlMEgKnHIYb35ItGhtFiTLQta9RkXx7vaeDwpOdPP/IvuvpjpQZkobRgBsk
-bNM0KuJpd2mSTphQAt6eKQIdcPrkzvc/Yh9OK3YNLUAbu/ZhBUnBvFnUL4wn2f1U
-mfO+m8P/LxybwqKx7r1mbaB+tP3RTxxLcIMvm9ECPQEoBntfEL325Wdoj+WuQH5Y
-IvcM6FaCTkQsNIPbaBD5l5MhMLHRULZujbDjXqGSvRMQfns6np/biMjNdQA8NZ5z
-STeUFvkQbCxoA0YYLgoSHL5KhZjXrg2g+T+2TUyCTR/91xf9OoOjBZdixR0S0DzJ
-B1+5vnUjZaCfnSEA7A==
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjNaGA8yMDUwMTEyODE0MzUyM1owIDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA4zzIHppVZvXu6OvdrJTrabEdCiqfgK8b3JeUm8Y4a/+6
+uxZWzRRgl1z3ouw1k3WzN2b1rI3MIjDd6Nr5QuyPEKLr7cszik7vog5Ev9cVqaVM
+9hsFnikd1lUHSedkACdYJk/Jd2eM4pDn7y6dVeR+JuSOPxQQsEnayd6Gw5r4JOQ4
+F7PPFgyrECBvLAshixbjjxuu6ftRelaapsYr5Kx0ZohnlJvtl7NzmW3oKst6ZNlM
+ccruXhZkUIISLi3eyA7yjW8MQsP8gTkbyXJe8h2AmDq3yyyl6vuILDpLzH6iSGOJ
+KNO8MtTaDgBqeplFkHj1o/BOjRBRwkDYEInEv3EvLwIDAQABo2UwYzAhBgNVHREE
+GjAYhwTAAAIBhxAgAQ24AAAAAAAAAAAAAAABMB0GA1UdDgQWBBSZsk0rfkcawCvx
+XxCfQdMrWBIAVTAfBgNVHSMEGDAWgBTyjzpmQFBkSCLXLoL/Vp7Cs+50CjANBgkq
+hkiG9w0BAQsFAAOCAQEAHtiw75o40lNQJPmdNJ0GijokFQ80AB9Cq1h3IAE7g9X4
+S5EQ+xukQoEcDwqi3PYN2axHayE3qgYpD4burydxboNFeDSl06Sv+g3KQ57Uv76y
+ODFOElKwedkdfgxVrBNX2kVR1gacQHrMqGN7aBSwZ8wReLS4keYtDo/Bfd9cyaBF
+g3CuPCa7u7ZB9S+g8bRE1L0rktQ9viynMI5G1hgFqm+aXMBpWrQj566z8qMRDN0a
+qk6gHxfXFy9NJorUxfHOTcrrKA2YciGHFUdRZT6zX4Nt8RjTWK6Oxro4G6UqAH+2
+g65OIDeyMwi+UUnDzMQPJoI20jZpBms9670yrlZDqg==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt b/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt
index 2be02feb03..cbf79b9112 100644
--- a/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt
+++ b/src/test/ssl/ssl/server-ip-cn-and-alt-names.crt
@@ -1,19 +1,21 @@
-----BEGIN CERTIFICATE-----
-MIIDHTCCAgWgAwIBAgIIICIBBBQ2MQAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDXzCCAkegAwIBAgIIICMHExY1IwUwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMjAxMDQyMjM2MzFaFw00OTA1MjIyMjM2MzFaMDQxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTESMBAGA1UEAwwJMTkyLjAuMi4x
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwmqTdQJfs2Ti9tPitYp2
-27I0HvL/kNSgA6egFr0foRo0BorwJNIzdbV0+EnsfiBNTWL5It26gqO7UP3ms8t2
-vHD5gkXfT+f6ts0lVJEcIOkUD/8ws4Ic9Y4uPqb4gN+pUKqcxtmLW1TYk84MBK59
-Xz4yPPS6N+G/DMMeFHTNkM9EQwn/+DC3fDsWdGYM2GRWDTJGg1A5tSUcF+seu7i1
-Vg7XajBfsvgAUAsrAxV+X/sLZh94HY+paD6wfaI99mY2OXVc/XW/z1r9WQznor65
-ZkonNCaPfavqPG5vqnab9AyQcqPqmX8hf/xrniASBAkqNCctbASrFCIYvCJfGfmX
-EQIDAQABoyUwIzAhBgNVHREEGjAYhwTAAAIChxAgAQ24AAAAAAAAAAAAAAABMA0G
-CSqGSIb3DQEBCwUAA4IBAQBf7kmYfRYfnWk1OUfY3N1kaNg9piBBlFr9g+OQn9KU
-zirkN7s0ZQbCGxV1uJQBKS58NyE414Vorau77379emgYDcCBpDIYpkLiNujVrIOr
-ggRFKsFRgxu4/mw0BSgCcV8RPe9SWHZ90Mos7TMCnW/PdxOCD1wD0YMkcs0rwB3l
-0Kzc7jDnfOEvmgw/Ysm7v67ps+05Uq5VskQ6WrpSAw6kPD/QMuuBAX8ATPczIaox
-zAMyncq1IiSIwG93f3EoQQThdQ70C6G9vLcu9TtL6JAsEMFEzR99gt1Wsqvmgl9W
-kStzj1yjIWeo5gIsa4Jgcke1lZviWyrTxHDfyunYE5i5
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMRIwEAYDVQQDDAkxOTIuMC4y
+LjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCapN1Al+zZOL20+K1
+inbbsjQe8v+Q1KADp6AWvR+hGjQGivAk0jN1tXT4Sex+IE1NYvki3bqCo7tQ/eaz
+y3a8cPmCRd9P5/q2zSVUkRwg6RQP/zCzghz1ji4+pviA36lQqpzG2YtbVNiTzgwE
+rn1fPjI89Lo34b8Mwx4UdM2Qz0RDCf/4MLd8OxZ0ZgzYZFYNMkaDUDm1JRwX6x67
+uLVWDtdqMF+y+ABQCysDFX5f+wtmH3gdj6loPrB9oj32ZjY5dVz9db/PWv1ZDOei
+vrlmSic0Jo99q+o8bm+qdpv0DJByo+qZfyF//GueIBIECSo0Jy1sBKsUIhi8Il8Z
++ZcRAgMBAAGjZTBjMCEGA1UdEQQaMBiHBMAAAgKHECABDbgAAAAAAAAAAAAAAAEw
+HQYDVR0OBBYEFGX9z+RX7x23a5ViEQbcj5XBGHaZMB8GA1UdIwQYMBaAFPKPOmZA
+UGRIItcugv9WnsKz7nQKMA0GCSqGSIb3DQEBCwUAA4IBAQCQQ+5/h6r84jks/l5u
+0G6w07hcgo/AfPEVSqGXDlEiJEdP8IownmxPB5siRwq6FNHqVMQ6usFeTlfYqtzE
+OmQOagLyKAhYCQkVPUIpIKLj70o8DVqnwoxr1+kWZUi4xLPTYPawFHUem7cX6TuT
+7TQe2yCXPHf8GaIMRjNI1LSpT5DUxHXZinw6UnsHr5EotFTSzmS/Yfko881+WDBq
+Uv/AOReEwLUvaRBTbWmIxyN7y6S8BUzlDw6AvSZLVczuQ1qLbFAc/fjdkiyCos2J
+r8FOq7UnBrvbs7/mT/1AtAcHjShPYGH3JFIgvHfixrJlsdS85f3GA9tJgJ9BV16d
+qkjO
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt b/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt
index 23c06da01c..b51dab2963 100644
--- a/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt
+++ b/src/test/ssl/ssl/server-ip-cn-and-dns-alt-names.crt
@@ -1,20 +1,21 @@
-----BEGIN CERTIFICATE-----
-MIIDQzCCAiugAwIBAgIIICIBBBQ2MQEwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDhzCCAm+gAwIBAgIIICMHExY1IwYwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMjAxMDQyMjM2MzFaFw00OTA1MjIyMjM2MzFaMDQxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTESMBAGA1UEAwwJMTkyLjAuMi4x
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8xddbo/x2TOSIa/br8BN
-o/URdTr9+l2R5YojiZKDuLxiQVkgC30PJ2/CNFKIh2nHhRrzknI6sETVtrxZ+9V2
-qRc1yShVu462u0DHPRMIZnZIOZg3hlNB0cRWbOglUKlttIARNEQUcTUyPOtyo4/v
-+u0Ej5NTNcHFbFT01vdD9MjQiCO3jKdAwPIb14jTg4C71EpZ+LuelDo4DzF2/XgG
-WqUTrgD/XnBU/60PU9Iy3G0nVpx21q6ppn9G7a9R+i8FjBcwW1T+cfsBDWhAv+bi
-RmSAkENf8L8TwOlDQUwROkfz3Hz36vuJjdkreQJsiqL0HnrnH5T5G9UzJO86FvZQ
-5wIDAQABo0swSTBHBgNVHREEQDA+gh1kbnMxLmFsdC1uYW1lLnBnLXNzbHRlc3Qu
-dGVzdIIdZG5zMi5hbHQtbmFtZS5wZy1zc2x0ZXN0LnRlc3QwDQYJKoZIhvcNAQEL
-BQADggEBAF+mfaw6iBPzpCgqq830pHRa3Yzm1aezt8SkeRohUYHNv/yCnDSRaqtj
-xbENih3lJMSTBL3g0wtTOHfH8ViC/h+lvYELHzXKic7gkjV7H5XETKGr0ZsjBBT2
-4cZQKbD9e0x0HrENXMYgGpBf747qL6uTOVJdG0s15hwpLq47bY5WUjXathejbpxW
-prmF8F+xaC52N9P/1VnqguQB909F4x1pyOK7D7tjFu+Y8Je7PHKbb6WY5K6xAv6t
-R17CY0749/FotlphquElUR2bs5Zzv5YrjUHPTcbwKvcH5cdNi93/u6NJt2xNAoYf
-aZERhX5TA9DYk4gC8OY0yGaYCIj3Dd4=
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowNDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMRIwEAYDVQQDDAkxOTIuMC4y
+LjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDzF11uj/HZM5Ihr9uv
+wE2j9RF1Ov36XZHliiOJkoO4vGJBWSALfQ8nb8I0UoiHaceFGvOScjqwRNW2vFn7
+1XapFzXJKFW7jra7QMc9Ewhmdkg5mDeGU0HRxFZs6CVQqW20gBE0RBRxNTI863Kj
+j+/67QSPk1M1wcVsVPTW90P0yNCII7eMp0DA8hvXiNODgLvUSln4u56UOjgPMXb9
+eAZapROuAP9ecFT/rQ9T0jLcbSdWnHbWrqmmf0btr1H6LwWMFzBbVP5x+wENaEC/
+5uJGZICQQ1/wvxPA6UNBTBE6R/PcfPfq+4mN2St5AmyKovQeeucflPkb1TMk7zoW
+9lDnAgMBAAGjgYwwgYkwRwYDVR0RBEAwPoIdZG5zMS5hbHQtbmFtZS5wZy1zc2x0
+ZXN0LnRlc3SCHWRuczIuYWx0LW5hbWUucGctc3NsdGVzdC50ZXN0MB0GA1UdDgQW
+BBSAWxUeTAXIo1H+cmx5bW0UJrPWlDAfBgNVHSMEGDAWgBTyjzpmQFBkSCLXLoL/
+Vp7Cs+50CjANBgkqhkiG9w0BAQsFAAOCAQEAoFdBPGtQA1y8lVAK3aFMyczeFwmS
+Bh+gIEyYpzWEUCgLManf6MnVpR1lG2nPasHawlHD0vmNBNuKHaKwtvXanNlnhK60
+mSyVx2tRVtygs+fCFykS3Oy0GlBWdoONyZWmwV97+Jpq7F2tb3fqCehy0HWFKruG
+JfVFBfVtPOdEgrla6ExuVcitDGNjKe6O1Kvt5m2Ze5+tX/rBJcSL9vfh/pa/qM4B
+lukCT9RwNNfUgNKIC0Tq13sNUeo7Fz3td46ZFOviBMv5ywH/7OE9eYNRvXwd/brH
+xNiRiUwBiUMvae38Tm4E8bFT6N/pmRVXAk4v84Eo/hxFIogT531JNaQhYA==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-cn-only.crt b/src/test/ssl/ssl/server-ip-cn-only.crt
index 9bf015cf18..8b15358577 100644
--- a/src/test/ssl/ssl/server-ip-cn-only.crt
+++ b/src/test/ssl/ssl/server-ip-cn-only.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC8TCCAdkCCCAhESkRN1IAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC8zCCAdsCCCAjBxMWNSMEMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjExMTI5MTkzNzUyWhcNNDkwNDE2MTkzNzUyWjA0MR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxEjAQBgNVBAMMCTE5Mi4wLjIuMTCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWs1uUL71nHYF9Zj6p+M3MpYDvx
-32iCjVdtH5a2qpSWHXTg0rR8dLX0y92cvOYvMXHRajZT1avpHr8dooPYSVaXpGMK
-NvF/Qi+WFYovRbP2vmd1yv1cgW/FggbwJFWVobizIz4seyA4d0B2j9fqoi2OFBNP
-huW664SjF0u3p21tDy+43i2LNUMAKf6dnRR5Vqenath87LEU41tSLudu6NXgbFMk
-jvfNkl4d0w7YCzeXmklmSI+uaX3PlJJ4NzQO2j8w5BvnKVhNVD0KjgrXZ6nB/8F7
-Pg3XY+d7rJlwRgXemU6resWQDJ7+UaC9u7I4EIP+9lzCR/nNBqUktpHRmHUCAwEA
-ATANBgkqhkiG9w0BAQsFAAOCAQEAos1JncV8Yf4UaKl6h1GdYtcVtzFyJvBEnhRD
-07ldL+TYnfZiX8wK2ssBtM3cg/C78y5bzdUa5XGS83ZKQJFFdhE7PSnrvyNqyIqY
-ZgNBxto3gyvir+EjO1u9BAB0NP3r3gYoHRDZS1xOPPzt4WgjuUgTLM9k82GsqAbO
-UrOTOdRnkIqC5xLpa05EnRyJPRsR1w1PRJC2XXKnHIuFjMb4v7UuPwyCcX1P5ioc
-rQszQcORy/L+k0ezCkyweORg68htjYbBHuwOuiGfok6yKKDMzrTvD3lIslls6eX7
-4sI3XWqzkPmG9Vsxm9Vu9/Ma+PRO76VyCoIwBd+Ufg5vNXhMmw==
+Y2VydHMwIBcNMjMwNzEzMTQzNTI0WhgPMjA1MDExMjgxNDM1MjRaMDQxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTESMBAGA1UEAwwJMTkyLjAuMi4xMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1azW5QvvWcdgX1mPqn4zcylg
+O/HfaIKNV20flraqlJYddODStHx0tfTL3Zy85i8xcdFqNlPVq+kevx2ig9hJVpek
+Ywo28X9CL5YVii9Fs/a+Z3XK/VyBb8WCBvAkVZWhuLMjPix7IDh3QHaP1+qiLY4U
+E0+G5brrhKMXS7enbW0PL7jeLYs1QwAp/p2dFHlWp6dq2HzssRTjW1Iu527o1eBs
+UySO982SXh3TDtgLN5eaSWZIj65pfc+Ukng3NA7aPzDkG+cpWE1UPQqOCtdnqcH/
+wXs+Dddj53usmXBGBd6ZTqt6xZAMnv5RoL27sjgQg/72XMJH+c0GpSS2kdGYdQID
+AQABMA0GCSqGSIb3DQEBCwUAA4IBAQB2VbIjlzU7ieisvO3ZCGMJmCmQtEDC8Xgo
+umbbHtCdCYtPy8KSulAKBzLLBpVsQiOqq6T8t3KZrU64Wi2DEamULfYfgZCdatQw
+EWzBmTOO+5guo3ntm57+3kR9pRbTDbLUgOrgJrKnu1THof+6gwX6e0D++91mfwpm
+FLhn4bIuRyQtlqH7Ft0otsA4HezoHDLGTS76NDYpx+rDklFE6ZUk3RFgC7ScXPfW
+rA+KJIATgnrDwBx+n8s1SeZ7S64QkZk27QVi/8exYbd6aJwWBTuoHXZswfn5nK/b
+PFR7RK0LgucLvOKjUTzNPZUyhjS+b2dSnPZUuWNTFFu5KhnfoPEZ
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-ip-in-dnsname.crt b/src/test/ssl/ssl/server-ip-in-dnsname.crt
index 78ad8d99c8..87009ebd2c 100644
--- a/src/test/ssl/ssl/server-ip-in-dnsname.crt
+++ b/src/test/ssl/ssl/server-ip-in-dnsname.crt
@@ -1,18 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIC/DCCAeSgAwIBAgIIICIDFRVYUgAwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDPjCCAiagAwIBAgIIICMHExY1IwcwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMjAzMTUyMjU4NTJaFw00OTA3MzEyMjU4NTJaMCAxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAMpn5bP1/OfBQR/yvOkOBzxArE1j1YShVa2pcj896+CVDEgV
-N5Hluz7KHU/JYzNZCAHb5WAHuvXxKeoj4Ti5be1KsqO0mN1p+RMN7VlCpCpb0AWT
-z4z+I8TUhSZnmgghHvfW4RfcZMCcHq1vevVTDxR/cAbDPYpgBCD5F/SZMRyMDw5B
-7ILLmft0eqA1nCqavyqBCGZvx1ol8N5BfVdrDXp/rN5997khBWQRZ8g84FZyFZXf
-pwp57eu0OGQDzZFXoEL2t4OVld67K5jcclWVxHY6FGcHjCvyqs48PCPOR84anZwj
-GsqVOS6250/DWKBQO4KyhkTVf0AW/ICGSMOKkAkCAwEAAaMYMBYwFAYDVR0RBA0w
-C4IJMTkyLjAuMi4xMA0GCSqGSIb3DQEBCwUAA4IBAQDIAAH0WJKEpbPN0QihN6SF
-UA5WL4ixsBACo9OIAGkSnKeOeVEG5vvgOna0hjQcOcgtI1oCDLhULcjCuwxiIW6y
-QntOazyo0sooJr0hEm2WfipvIpQs6W9E1OTcs624BAVfkAwr6WT2VwoIAPcQD2nR
-tIQhSUIR9J7Q5WbzuQw7pthQhBfW/UPWw7vajel0r1dflbe0Cgp5WGNfp1kYy+Qf
-XW/YjkstZEP1KFm+TF58uxrIDmYboS8EerUREGQixijbI0AfXjShxtiyS63rbdpo
-3C0BPj9Yx2VtWi4U0qoef/iLJxJBCLvE/97+duPdKx0AkkOWA9VuenkWLp797UM8
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowIDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAymfls/X858FBH/K86Q4HPECsTWPVhKFVralyPz3r4JUM
+SBU3keW7PsodT8ljM1kIAdvlYAe69fEp6iPhOLlt7Uqyo7SY3Wn5Ew3tWUKkKlvQ
+BZPPjP4jxNSFJmeaCCEe99bhF9xkwJwerW969VMPFH9wBsM9imAEIPkX9JkxHIwP
+DkHsgsuZ+3R6oDWcKpq/KoEIZm/HWiXw3kF9V2sNen+s3n33uSEFZBFnyDzgVnIV
+ld+nCnnt67Q4ZAPNkVegQva3g5WV3rsrmNxyVZXEdjoUZweMK/Kqzjw8I85Hzhqd
+nCMaypU5LrbnT8NYoFA7grKGRNV/QBb8gIZIw4qQCQIDAQABo1gwVjAUBgNVHREE
+DTALggkxOTIuMC4yLjEwHQYDVR0OBBYEFDGGF+fm5mk/sd23jkLL3uVU0NjCMB8G
+A1UdIwQYMBaAFPKPOmZAUGRIItcugv9WnsKz7nQKMA0GCSqGSIb3DQEBCwUAA4IB
+AQCf8knuWhoBZ8psmq+NC/RZRxfQmFBRj+bKzJ6YaAHyNmE44nBtIAJal3m4FyTZ
+vXAlYpfRLrF+R5PJVnvT8mfu/vfxJn3MPHV7R8vmJpRAx8uQKFuxQPQDUq84efqZ
+BHG0zoNPml915nVfxgt1WqIVWQpomAOvjb1Ct31A1bZF5oMjhg86XdytqQNohl8I
+NBNu027tO0izM/mX3xJzYEnBSiHwKPfZxSKtc0FSffwohWUlpEye1A4Q9d6tWF6d
++PagUG+hodSLsU5Bno4dc0RYJr9xJLW9QMcuCbMC9zXaUBWpkUwOWbMXpPhvawdu
+oR2Tvhha37JD6a8NEUgSJOvL
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-multiple-alt-names.crt b/src/test/ssl/ssl/server-multiple-alt-names.crt
index 58799e49f8..85663b97af 100644
--- a/src/test/ssl/ssl/server-multiple-alt-names.crt
+++ b/src/test/ssl/ssl/server-multiple-alt-names.crt
@@ -1,20 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIDSzCCAjOgAwIBAgIIICEDAxQSBwMwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDjzCCAnegAwIBAgIIICMHExY1IwkwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTAzMDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMCAxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBANdIkKX1X+Jwqo5EXC1z/TjUKnYTDzHYx2rCqprBU8fN0mSy
-lMyjDm+eo924PN7LahqCHeDCMbapwymkoNfpLHkNRwotHLvxN5RyxJD4m5fXclRo
-V1ZzwwXTqXlECwrzzYGst/7muDM9DX+0vXIAvQGbvxBGI0CBM3ztHBADXlSFrYGX
-zN/to9KZmeOgBGJRGSZJg09P5px5N2E49yOqkIa9+MGb6nK8KLmETeTYjlWCS6W+
-oD0qGpZvj2Fzioz+Pn1q9fB3WS687GuMT0WvV3LAzcn341r0E36bUf9rxSjfBX79
-11KsVMemr1QskSmvMQFEv6R1Rp8xUGPqKlkRJ9sCAwEAAaNnMGUwYwYDVR0RBFww
-WoIdZG5zMS5hbHQtbmFtZS5wZy1zc2x0ZXN0LnRlc3SCHWRuczIuYWx0LW5hbWUu
-cGctc3NsdGVzdC50ZXN0ghoqLndpbGRjYXJkLnBnLXNzbHRlc3QudGVzdDANBgkq
-hkiG9w0BAQsFAAOCAQEAuRAyYBwAZLKERoYDy/kE9LKddJfLhledTJ7+cIWs6T9V
-KBfWBHZYxfxmdBYwqVZfog8c5uHREfWiUPoF/aMq3ARay96aMh4xXJ+2a7HAmknF
-9AJWRieoc3H/QkMzAuT8IDTmoEarsr8vsX1MGabobZte/B9tEjq/z5t3GfLrHMVX
-5092U6Ka40ii4U1VwjR8YnRBwjm3UpLmZJAjvXjw13/XucNV5O8Plo1yvS+G0AMh
-KdMxExiItVtjZteiA0pJf0YGAzTFyzvwBljTcs4NfZ2M0ta9i0r4BF7wQ8tDezN7
-VxdJVPc5xPqncp0cMdUAE2xDmYlKEqB0kuAHNwH5/Q==
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowIDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA10iQpfVf4nCqjkRcLXP9ONQqdhMPMdjHasKqmsFTx83S
+ZLKUzKMOb56j3bg83stqGoId4MIxtqnDKaSg1+kseQ1HCi0cu/E3lHLEkPibl9dy
+VGhXVnPDBdOpeUQLCvPNgay3/ua4Mz0Nf7S9cgC9AZu/EEYjQIEzfO0cEANeVIWt
+gZfM3+2j0pmZ46AEYlEZJkmDT0/mnHk3YTj3I6qQhr34wZvqcrwouYRN5NiOVYJL
+pb6gPSoalm+PYXOKjP4+fWr18HdZLrzsa4xPRa9XcsDNyffjWvQTfptR/2vFKN8F
+fv3XUqxUx6avVCyRKa8xAUS/pHVGnzFQY+oqWREn2wIDAQABo4GoMIGlMGMGA1Ud
+EQRcMFqCHWRuczEuYWx0LW5hbWUucGctc3NsdGVzdC50ZXN0gh1kbnMyLmFsdC1u
+YW1lLnBnLXNzbHRlc3QudGVzdIIaKi53aWxkY2FyZC5wZy1zc2x0ZXN0LnRlc3Qw
+HQYDVR0OBBYEFNQECIqqAsJFZk9MZ3oygGNRbziXMB8GA1UdIwQYMBaAFPKPOmZA
+UGRIItcugv9WnsKz7nQKMA0GCSqGSIb3DQEBCwUAA4IBAQDOljab+EBwmJA4qzN4
+nY3QVQWxoPG7RBrNFRp2hrP05amitsjWG4+GWiIlKT7aSpEgUghdZgAb25FG44VH
+oUEo2aAJjTRGmssbeOUstDRXYCIOefaaxSleEgbZdrUb+zDkPwDw381EYuO/E+og
+OcS9nsbrq1vo1B09xQdpcJ6pf9VmmM4OQHpD2/xPxhOPVxMKhbrFvVOlHDc23sue
+kfaAnHFu3k5O2/fqGxWm7IQA8KNfhyWRDDZjwU3F+duqiHphGDyn0JH6bO+QNSEs
+kj7tCGh9oziomt/mnD1zDPO+s9f5+i9itk8emRaBakLsv7SyngO777r79myiiM+E
+LYJo
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-no-names.crt b/src/test/ssl/ssl/server-no-names.crt
index b5d0589090..45a434bcf1 100644
--- a/src/test/ssl/ssl/server-no-names.crt
+++ b/src/test/ssl/ssl/server-no-names.crt
@@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
-MIIC3TCCAcUCCCAhAwMUEgcEMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIC3zCCAccCCCAjBxMWNSMKMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjAgMR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQCfOf74edog2QHkJlreO6NJEe1VZUSxn+LBeHH8T5fniFiM4Ym9X2o3
-XKhYsvNSwvrfWwMkajMkd3b3vURiuiAxYzB/9AwX97RUkZ8TfuU3UgISiCbJZrVH
-TpfJEv7JhePgYpAoOdPWqtFPmnO/Xv6uNjsrx/V/3COovUj3eIcyQzAl+eC2U9Tn
-//dJ0kF+hDnOR3I/3e6bAboJjAVvLl2ABryaateHuUaCu/Bf5mG1DarXNXPKYuP+
-KrkjHhH0KQ4Js3nu7bPEiG0E/JmCR452j72WKb+PiJHOxdMMyztZ3k6bGGlbw60j
-CwQnUJAlPL4G9U+lpVYG6f7HxOaJEscfAgMBAAEwDQYJKoZIhvcNAQELBQADggEB
-AJAwYwIL4oj3NisXCXkEp9zqDXiZvNW9yW3bY8lFFCpU7o5n92tCf2OFAkKaYhF1
-Eb2weyDULtW7W/wgdlOZL9npayYKzTusl6e8xfTQyjRCsoKWvnWOEkPH7VraZJ8c
-Ko1KhaVWX98VLdlUh5giYAEkdhk0qPYKsQ32unBXXJu0pX63pnPDoaUBiZUWr/3l
-CfkjgGY5YA8YxiDlHGNF1qlcX2fQKloDlvtH0L5Enwt25w2/IvWhTN6YxDR+rgdD
-XYbQr6o6vsmnZTJ3zUZ6XFo98sZq5L9oy1pcC8roV7w0AUVxraTWYILyGfNgruG8
-xsok/hu1L2VnktveEW/qoVs=
+Y2VydHMwIBcNMjMwNzEzMTQzNTI0WhgPMjA1MDExMjgxNDM1MjRaMCAxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAJ85/vh52iDZAeQmWt47o0kR7VVlRLGf4sF4cfxPl+eIWIzhib1f
+ajdcqFiy81LC+t9bAyRqMyR3dve9RGK6IDFjMH/0DBf3tFSRnxN+5TdSAhKIJslm
+tUdOl8kS/smF4+BikCg509aq0U+ac79e/q42OyvH9X/cI6i9SPd4hzJDMCX54LZT
+1Of/90nSQX6EOc5Hcj/d7psBugmMBW8uXYAGvJpq14e5RoK78F/mYbUNqtc1c8pi
+4/4quSMeEfQpDgmzee7ts8SIbQT8mYJHjnaPvZYpv4+Ikc7F0wzLO1neTpsYaVvD
+rSMLBCdQkCU8vgb1T6WlVgbp/sfE5okSxx8CAwEAATANBgkqhkiG9w0BAQsFAAOC
+AQEA1w+EnZ8ef189KqulzF9vrKjdavlFyWon+otR0WAKFOojNMyIgAkbU69N0CHO
+LnJPiIF3H3izWelNo+2Wv3BxylQXgRlr92gUCFoEQ/RKnZVjgKl36e2+l/AVud1Q
+ke343xnYLup/jQ7LzKFIdyxmO090rrlHUO7Dg7bJAuHQ9bRbCO+orAg4nFZEoKd1
+kO/XQ7e18l95QJE6vOmRcbD0+kGRNYBA2v6K3DwX0PRUm7fyP1gLTbIt6jGukQiJ
+/ZkcvVcHNkcJzEr+A8BGVYgTG6VhuBPSMWVnnZcui93vH2D/3hq7ILNlFWBycSW6
+HheriPQ4X+y96SmttrjQVwSDYA==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-revoked.crt b/src/test/ssl/ssl/server-revoked.crt
index 3bb0f164a6..ce4350dbc6 100644
--- a/src/test/ssl/ssl/server-revoked.crt
+++ b/src/test/ssl/ssl/server-revoked.crt
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIIDAzCCAesCCCAhAwMUEgcFMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
+MIIDBTCCAe0CCCAjBxMWNSMLMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl
c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBzZXJ2ZXIg
-Y2VydHMwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBGMR4wHAYDVQQL
-DBVQb3N0Z3JlU1FMIHRlc3Qgc3VpdGUxJDAiBgNVBAMMG2NvbW1vbi1uYW1lLnBn
-LXNzbHRlc3QudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKKD
-zvJUs+N+KeDwWAW0zfI5C1t3BxKUwh+MrwtFeNIcxhJd9Bzy6fNnvpMa/kNPoHfN
-n73OGLYeSDyiDc56dvBjLOfxPXFFN4TCuIxYSizIjniL3tzP/a8hyvO+KqTYyaEs
-cT8+/rNnqlqBXNqcdChSGpk0y34uybvWj2/wDJWTbFJ20bI+30HOxCfK8Dp3s8Nl
-suVSuLKF/qqbidDZuOAKc0/GJo2F/5AF9MkMYELmG6XAVq/XDkI3oLtxQKh6kYfc
-nu3fI0Mwr9+FoP2q+K5KskA3KJLlgBOykG55Odbe6Js4TPHrMBTgC9aWrP/I1gb8
-tFY2FVN+D/Wl8T/Boh0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAxVHoqX25W4Hx
-pMNjv2AJzcB7D+c+dUXAmLLJ7jh6szWeL0M2E5qX4dLc8LzQKnXv5ZcT4i/akjDX
-etdzuqh03kvDJvUkHclSWffmowmWMTG6GCA6S/2TQzSibIptkwqs74aIkayVJaC4
-jCBR+PVT8+cE2FMD6dAWu//fyEcpTg6XpZ/Upgu9OITGNaEQUGz8pSRkTgspfO0Q
-AKPmql6dpywReIlr5mzy9liCzf/BbAVHGmP/pBGIkLn2AzvPLCQ/UFZYT6aH7l5J
-nzmFhgRC3U5wPMdelHGrPMXg6OHCcyrQY0kEi7N/GQ5+jZkICoQuPJ7APKEZAUgO
-XRwVulaWJQ==
+Y2VydHMwIBcNMjMwNzEzMTQzNTI0WhgPMjA1MDExMjgxNDM1MjRaMEYxHjAcBgNV
+BAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTEkMCIGA1UEAwwbY29tbW9uLW5hbWUu
+cGctc3NsdGVzdC50ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+ooPO8lSz434p4PBYBbTN8jkLW3cHEpTCH4yvC0V40hzGEl30HPLp82e+kxr+Q0+g
+d82fvc4Yth5IPKINznp28GMs5/E9cUU3hMK4jFhKLMiOeIve3M/9ryHK874qpNjJ
+oSxxPz7+s2eqWoFc2px0KFIamTTLfi7Ju9aPb/AMlZNsUnbRsj7fQc7EJ8rwOnez
+w2Wy5VK4soX+qpuJ0Nm44ApzT8YmjYX/kAX0yQxgQuYbpcBWr9cOQjegu3FAqHqR
+h9ye7d8jQzCv34Wg/ar4rkqyQDcokuWAE7KQbnk51t7omzhM8eswFOAL1pas/8jW
+Bvy0VjYVU34P9aXxP8GiHQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQDCJoMLMIl8
+yvxrXH+kD2z163bwsMEIdsJxsXGjewmI/tDMyDLdYVQGJm9YRa/Oebylir7T+ayr
+NGj7b+Uo5KezgnRw9iQ9U8Xz6oKNxMNHB0mw5v7eR2cDFTzzNm1jYReIxWVryLOj
+al4C5uWqoIOHUNYibSJZIjNpzR/Zu4d/Ijt3+oJz9OFRXlaXYuDqLrm8hsUkxBm8
+s6GS79Dvw75M689ZKrKQs/15ceFYqx1hTvePW7kK5tuhW//Hf2IX4pwwtn5x0t4A
+M47qO71Zo3BxJFToNgALaw2+ixWNqy4kZ429NQjXArtq6eUI6IaOTU1ER2UAcOjN
+OOC5mBDmmMZa
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server-single-alt-name.crt b/src/test/ssl/ssl/server-single-alt-name.crt
index 7affdd68e7..077a60a7ad 100644
--- a/src/test/ssl/ssl/server-single-alt-name.crt
+++ b/src/test/ssl/ssl/server-single-alt-name.crt
@@ -1,19 +1,20 @@
-----BEGIN CERTIFICATE-----
-MIIDEjCCAfqgAwIBAgIIICEDAxQSBwIwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
+MIIDVDCCAjygAwIBAgIIICMHExY1IwgwDQYJKoZIhvcNAQELBQAwQjFAMD4GA1UE
Aww3VGVzdCBDQSBmb3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHNl
-cnZlciBjZXJ0czAeFw0yMTAzMDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMCAxHjAc
-BgNVBAsMFVBvc3RncmVTUUwgdGVzdCBzdWl0ZTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAMWKHC1lrog7A8ye8C3NM38JBiQBMuIZR40wORl0hJxj5Tp8
-dX8Xo2Thi9Ry33+YfMwfkkF66ZRwnMMEa8VYBmOz+fZFzF19WpE8F1CR3PxKE7ai
-zvunxy8oMxdXdIuTTzt8a5NcDLe22C4Yj21qaZVoh182ycvMH93V4MwsLcV3/GdV
-Ko7QpwP2ZCf5D1rhyccx+Trwyb2bKvhW5Jd3GrRacFJQFfUyrAu/FvyuSPmn86ab
-Jkr7CCgFlg6e4O9SFY7yXiOgLotsoQ5/YriTLinvUTGCMCSxaol97qx3I2gUpCZu
-i7H+4Dt9L5FcCMshl0TU32dsjw6El1Wbzp6voCsCAwEAAaMuMCwwKgYDVR0RBCMw
-IYIfc2luZ2xlLmFsdC1uYW1lLnBnLXNzbHRlc3QudGVzdDANBgkqhkiG9w0BAQsF
-AAOCAQEAUIhBQLzQgd7wHlT9DARxcC7SZwQtnk2BVqMYTRBU4uIa0i2HVyetpe1P
-rREthYq5sgaSqdonD9Splg8BLUlah9y3v9j6DBxkxNnz/3AZuA5oPaC/TZ+lwlX3
-QNWWFNaNZdcQbvjUvoPXIbJ6U9UDfByOJdoN4kJ6xe8Faj1Mp5Euqzr1ErrMtPWJ
-XLnXLV4WyAx+iMAbofXNlCyUorPGA8lRudzQ7bKdrhMZDE66VYwlwsUejEiODt7M
-NGTDs4aAZz9cBRjMeXhvX60cFQoykjAvWbieUKOgaFmJJyKemFj12cLeWyxvUodI
-kYtgAdzftiCSrbDjl1pzPSM6RC/E/A==
+cnZlciBjZXJ0czAgFw0yMzA3MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowIDEe
+MBwGA1UECwwVUG9zdGdyZVNRTCB0ZXN0IHN1aXRlMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAxYocLWWuiDsDzJ7wLc0zfwkGJAEy4hlHjTA5GXSEnGPl
+Onx1fxejZOGL1HLff5h8zB+SQXrplHCcwwRrxVgGY7P59kXMXX1akTwXUJHc/EoT
+tqLO+6fHLygzF1d0i5NPO3xrk1wMt7bYLhiPbWpplWiHXzbJy8wf3dXgzCwtxXf8
+Z1UqjtCnA/ZkJ/kPWuHJxzH5OvDJvZsq+Fbkl3catFpwUlAV9TKsC78W/K5I+afz
+ppsmSvsIKAWWDp7g71IVjvJeI6Aui2yhDn9iuJMuKe9RMYIwJLFqiX3urHcjaBSk
+Jm6Lsf7gO30vkVwIyyGXRNTfZ2yPDoSXVZvOnq+gKwIDAQABo24wbDAqBgNVHREE
+IzAhgh9zaW5nbGUuYWx0LW5hbWUucGctc3NsdGVzdC50ZXN0MB0GA1UdDgQWBBRE
+be2UnhcFV/bd5hEMML2w60NbbTAfBgNVHSMEGDAWgBTyjzpmQFBkSCLXLoL/Vp7C
+s+50CjANBgkqhkiG9w0BAQsFAAOCAQEA1pyC1Vb1EOgMdcdMq+u0FI+7GHGkEeg7
+qWMcLvu7mbcbcyzLriBUk1vKDYw+6WspTc6vvqMGxNVdwchm/93rUM/JI4C6nrmr
+3TJqE578C3EI+4YZxLLRnfYWBO0uyUfLkdjT3n0Tnu643wYYoKOgpZRV2WgfktK6
+KoRqWlkXkVoV/qZUS9O67XtNttvCFMrPiM4YbGmwQ7lUZ9qzojy4Fb0AWcZOVEIy
+2b7FMOUrIzk9CgTRtEqeobSD98p3OXGtzVZf2hY9vLgA1hnbVjmB2Kt3QMhnicvt
+/Z7o8o88cmcrs0PXMe90tt1JBssTFs6+ARCsgUkEwzCRnvVX+Yky9w==
-----END CERTIFICATE-----
diff --git a/src/test/ssl/ssl/server.crl b/src/test/ssl/ssl/server.crl
index 331a83cb62..7ed68e0220 100644
--- a/src/test/ssl/ssl/server.crl
+++ b/src/test/ssl/ssl/server.crl
@@ -1,11 +1,11 @@
-----BEGIN X509 CRL-----
-MIIBpTCBjjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
-b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMTAz
-MDMyMjEyMDdaFw00ODA3MTkyMjEyMDdaMBswGQIIICEDAxQSBwUXDTIxMDMwMzIy
-MTIwN1owDQYJKoZIhvcNAQELBQADggEBAJxj0taZYIIxUsCuXR5CN2OymjMvRwmV
-+10VOkyBQ3VkzHlXeJkmZsU2Dvmc205l9OYouh/faL0TfK2NyhmBo+MrTizL9TBo
-4u2es/0oJGj2wyNMkRs0SlSJelakvGFBvSKfqoV0l2O1WDV7M4KtdC8ZVZipmL4R
-ac4hBMK0ifHuTS5Od6o0C2RijEPCHMXaS/LkWpBqcStI2oirhjo+Th1wxTMGUVFy
-imVvt6D6QqqHCUYrvcNEN0xBNFwJGq/0cgSy+w5szt/RRehmJKX8MbNeZxrznIIx
-B18ch9rbBltz+Y4R63rCN9MdsnGXf6PQ6a6doZhSI1pnDrui12MOQrU=
+MIIBpzCBkDANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0yMzA3
+MTMxNDM1MjRaGA8yMDUwMTEyODE0MzUyNFowGzAZAgggIwcTFjUjCxcNMjMwNzEz
+MTQzNTI0WjANBgkqhkiG9w0BAQsFAAOCAQEADIkF8oS84O2PJw/C9BAzgrkd+EsO
+QL6mXUGBgXwmujfpv0Z8YK91k4+xV9hQRMjWe/DkU01+gmFhYoDvAzweuNQzx8lZ
+bYKu0dGTEpTd+OG1LbxYmt4f5xh096R5iLo7c7e2kMHvfNG7VwvKQrPeMqh7AcKy
+Fukt8C0Xc7Tfv2l2toEQUAl5UDUKEAovN6iB0qycpvi0nboyiDo8mV0p1jlAn846
+EeXjwm8tyGXzTFq16ypPwnlBM9d5Ml/p5WTN69nDux18G+iSCr+UDzLDYvLF11p3
+lEqpSo5lQg9zYuOgMCvu3g5BtwJgORPSiW/yZ5BXUfWvPi0XRPrknxMByA==
-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/server_ca.crt b/src/test/ssl/ssl/server_ca.crt
index 0d6d7a6f82..8b010e7ca4 100644
--- a/src/test/ssl/ssl/server_ca.crt
+++ b/src/test/ssl/ssl/server_ca.crt
@@ -1,19 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIDFDCCAfygAwIBAgIIICEDAxQSBwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
+MIIDnjCCAoagAwIBAgIIICMHExY1IwAwDQYJKoZIhvcNAQELBQAwQDE+MDwGA1UE
Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
-c3Qgc3VpdGUwHhcNMjEwMzAzMjIxMjA3WhcNNDgwNzE5MjIxMjA3WjBCMUAwPgYD
-VQQDDDdUZXN0IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qg
-c2VydmVyIGNlcnRzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4kp2
-GW5nPb6QrSrtbClfZeutyQnHrm4TMPBoNepFdIVxBX/04BguM5ImDRze/huOWA+z
-atJAQqt3R7dsDwnOnPKUKCOuHX6a1aj5L86HtVgaWTXrZFE5NtL9PIzXkWu13UW0
-UesHtbPVRv6a6fB7Npph6hHy7iPZb009A8/lTJnxSPC39u/K/sPqjrVZaAJF+wDs
-qCxCZTUtAUFvWFnR/TeXLWlFzBupS1djgI7PltbJqSn6SKTAgNZTxpRJbu9Icp6J
-/50ELwT++0n0KWVXNHrDNfI5Gaa+SxClAsPsei2jLKpgR6QFC3wn38Z9q9LjAVuC
-+FWhoN1uhYeoricEXwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
-CwUAA4IBAQCdCA/EoXrustoV4jJGbkdXDuOUkBurwggSNBAqUBSDvCohRoD77Ecb
-QVuzPNxWKG+E4PwfUq2ha+2yPONEJ28ZgsbHq5qlJDMJ43wlcjn6wmmAJNeSpO8F
-0V9d2X/4wNZty9/zbwTnw26KChgDHumQ0WIbCoBtdqy8KDswYOvpgws6dqc021I7
-UrFo6vZek7VoApbJgkDL6qYADa6ApfW43ThH4sViFITeYt/kSHgmy2Udhs34jMM8
-xsFP/uYpRi1b1glenwSIKiHjD4/C9vnWQt5K3gRBvYukEj2Bw9VkNRpBVCi0cOoA
-OuwX3bwzNYNbZQv4K66oRpvuoEjCNeHg
+c3Qgc3VpdGUwIBcNMjMwNzEzMTQzNTIzWhgPMjA1MDExMjgxNDM1MjNaMEIxQDA+
+BgNVBAMMN1Rlc3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVz
+dCBzZXJ2ZXIgY2VydHMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDi
+SnYZbmc9vpCtKu1sKV9l663JCceubhMw8Gg16kV0hXEFf/TgGC4zkiYNHN7+G45Y
+D7Nq0kBCq3dHt2wPCc6c8pQoI64dfprVqPkvzoe1WBpZNetkUTk20v08jNeRa7Xd
+RbRR6we1s9VG/prp8Hs2mmHqEfLuI9lvTT0Dz+VMmfFI8Lf278r+w+qOtVloAkX7
+AOyoLEJlNS0BQW9YWdH9N5ctaUXMG6lLV2OAjs+W1smpKfpIpMCA1lPGlElu70hy
+non/nQQvBP77SfQpZVc0esM18jkZpr5LEKUCw+x6LaMsqmBHpAULfCffxn2r0uMB
+W4L4VaGg3W6Fh6iuJwRfAgMBAAGjgZcwgZQwDAYDVR0TBAUwAwEB/zAdBgNVHQ4E
+FgQU8o86ZkBQZEgi1y6C/1aewrPudAowZQYDVR0jBF4wXKFEpEIwQDE+MDwGA1UE
+Aww1VGVzdCByb290IENBIGZvciBQb3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRl
+c3Qgc3VpdGWCFBfnvJQgNLw9MyrcSA1T3Q2PyJIFMA0GCSqGSIb3DQEBCwUAA4IB
+AQANlEDrM357a7o+WcKB0Ocll2UtBMq7PDms1Pjqm3fFu/wdKDUomG8W2/MgDmFl
+CVeAPpofb6J0oaxiEZOR68pOhdccMznArtKix6t3RkDiXdm4d5UORMMR+s9CymXV
+MUTWpQpAg3qP3mRI+3E9OrgfhvmVcuOa7/cdTS/sylGe8Db+nJQD0be9NHtnhO56
+IA+Li+8oWzD4UNsP3gAmhLkyToz5wlPHzEkgGxkEySNErEOKTOX5Xyk5z+QToRhz
+adkt0mBw/dxoJk9DveCtIqxDelxJsDeJFtqoc5qVVE9yOp7rujGsqgWl2PcJeyKM
+Crh9qsqNzJ2R29pq0g6Lfzh2
-----END CERTIFICATE-----
--
2.32.1 (Apple Git-133)
v6-0002-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patchapplication/octet-stream; name=v6-0002-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patchDownload
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..78a5a83d5c 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 999456d3a4..215b01daff 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..9d64d2bfa4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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 timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notbefore'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notafter() RETURNS timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..c3b95e7d60 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#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 +35,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_timestamp(ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -225,6 +227,37 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into timestamp
+ *
+ * Parameter: time - OpenSSL ASN1_TIME structure.
+ *
+ * Returns Datum, which can be directly returned from a C language SQL
+ * function.
+ */
+static Datum
+ASN1_TIME_to_timestamp(ASN1_TIME * time)
+{
+ struct tm tm_time;
+ struct pg_tm pgtm_time;
+ Timestamp ts;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ pgtm_time.tm_sec = tm_time.tm_sec;
+ pgtm_time.tm_min = tm_time.tm_min;
+ pgtm_time.tm_hour = tm_time.tm_hour;
+ pgtm_time.tm_mday = tm_time.tm_mday;
+ pgtm_time.tm_mon = tm_time.tm_mon + 1;
+ pgtm_time.tm_year = tm_time.tm_year + 1900;
+
+ if (tm2timestamp(&pgtm_time, 0, NULL, &ts))
+ elog(ERROR, "timestamp out of range");
+
+ PG_RETURN_TIMESTAMP(ts);
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +515,35 @@ ssl_extension_info(PG_FUNCTION_ARGS)
/* All done */
SRF_RETURN_DONE(funcctx);
}
+
+/*
+ * Returns current client certificate notBefore timestamp in
+ * timestamp 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_timestamp(X509_get_notBefore(cert));
+}
+
+/*
+ * Returns current client certificate notAfter timestamp in
+ * timestamp 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_timestamp(X509_get_notAfter(cert));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 588b720f57..42c7808f50 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2257,6 +2257,26 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
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 UTC 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 UTC timestamp of the client certificate, or NULL if no client
+ certificate was supplied.
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..06f5728096 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -240,6 +240,36 @@ emailAddress
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notbefore() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notbefore</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not before</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notafter() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notafter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not after</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index af65af6bdd..f7c2cfb8cd 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -970,7 +970,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 658b09988d..41aa0cf720 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -36,6 +36,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 +73,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 Timestamp ASN1_TIME_to_timestamp(ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool SSL_initialized = false;
@@ -1406,6 +1408,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, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notBefore(port->peer));
+ else
+ *ptr = 0;
+}
+
+void
+be_tls_get_peer_not_after(Port *port, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notAfter(port->peer));
+ else
+ *ptr = 0;
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1549,6 +1569,31 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a cstring in format of YYYY-MM-DDThh:mm:ssZ.
+ */
+static Timestamp
+ASN1_TIME_to_timestamp(ASN1_TIME * time)
+{
+ struct tm tm_time;
+ struct pg_tm pgtm_time;
+ Timestamp ts;
+
+ ASN1_TIME_to_tm(time, &tm_time);
+
+ pgtm_time.tm_sec = tm_time.tm_sec;
+ pgtm_time.tm_min = tm_time.tm_min;
+ pgtm_time.tm_hour = tm_time.tm_hour;
+ pgtm_time.tm_mday = tm_time.tm_mday;
+ pgtm_time.tm_mon = tm_time.tm_mon + 1;
+ pgtm_time.tm_year = tm_time.tm_year + 1900;
+
+ if (tm2timestamp(&pgtm_time, 0, NULL, &ts))
+ elog(ERROR, "timestamp out of range");
+
+ return ts;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 38f91a495b..02dc9d7931 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -367,6 +367,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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 2a4c8ef87f..9071981f98 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -303,7 +303,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);
@@ -395,7 +395,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
pfree(clipped_activity);
/* leader_pid */
- nulls[29] = true;
+ nulls[31] = true;
proc = BackendPidGetProc(beentry->st_procpid);
@@ -432,8 +432,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)
{
@@ -441,8 +441,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;
}
}
}
@@ -587,35 +587,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] = TimestampGetDatum(beentry->st_sslstatus->ssl_not_before);
+ else
+ nulls[25] = true;
+
+ if (beentry->st_sslstatus->ssl_not_after != 0)
+ values[26] = TimestampGetDatum(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
{
@@ -645,6 +655,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 6996073989..878c997e87 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5413,9 +5413,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,timestamp,timestamp,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 => '3318',
descr => 'statistics: information about progress of backends running maintenance command',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index a0b74c8095..02765ba9d9 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -298,6 +298,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, Timestamp *ptr);
+extern void be_tls_get_peer_not_after(Port *port, Timestamp *ptr);
/*
* Get the server certificate hash for SCRAM channel binding type
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 77939a0aed..1e4fedb661 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -61,6 +61,8 @@ typedef struct PgBackendSSLStatus
char ssl_client_serial[NAMEDATALEN];
char ssl_issuer_dn[NAMEDATALEN];
+ Timestamp ssl_not_before;
+ Timestamp ssl_not_after;
} PgBackendSSLStatus;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index e07afcd4aa..30108846c1 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1760,7 +1760,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,
@@ -1878,7 +1878,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,
@@ -2080,7 +2080,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,
@@ -2113,8 +2113,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 76442de063..bad41cacc8 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -543,8 +543,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.
@@ -745,8 +745,8 @@ command_like(
'-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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E\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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E,\Q2023-06-29 01:01:01\E,\Q2050-01-01 01:01:01\E\r?$}mx,
'pg_stat_ssl with client certificate');
# client key with wrong permissions
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 5306aad802..f050a6f4f9 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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 = '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 = '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';",
On 17 Jul 2023, at 20:26, Cary Huang <cary.huang@highgo.ca> wrote:
Perhaps calling "tm2timestamp(&pgtm_time, 0, NULL, &ts)" without checking the return code would be just fine. I see some other usages of tm2timstamp() in other code areas also skip checking the return code.
I think we want to know about any failures, btu we can probably make it into an
elog() instead, as it should never fail.Yes, sure. I have corrected the error message to elog(ERROR, "timestamp out of range") on a rare tm2timestamp() failure.
I went over this again and ended up pushing it along with a catversion bump.
Due to a mistake in my testing I didn't however catch that it was using an API
only present in OpenSSL 1.1.1 and higher, which caused buildfailures when using
older OpenSSL versions, so I ended up reverting it again (leaving certificate
changes in place) to keep the buildfarm green.
Will look closer at an implementation which works across all supported versions
of OpenSSL when I have more time.
--
Daniel Gustafsson
On 20 Jul 2023, at 17:24, Daniel Gustafsson <daniel@yesql.se> wrote:
On 17 Jul 2023, at 20:26, Cary Huang <cary.huang@highgo.ca> wrote:
Perhaps calling "tm2timestamp(&pgtm_time, 0, NULL, &ts)" without checking the return code would be just fine. I see some other usages of tm2timstamp() in other code areas also skip checking the return code.
I think we want to know about any failures, btu we can probably make it into an
elog() instead, as it should never fail.Yes, sure. I have corrected the error message to elog(ERROR, "timestamp out of range") on a rare tm2timestamp() failure.
I went over this again and ended up pushing it along with a catversion bump.
Due to a mistake in my testing I didn't however catch that it was using an API
only present in OpenSSL 1.1.1 and higher, which caused buildfailures when using
older OpenSSL versions, so I ended up reverting it again (leaving certificate
changes in place) to keep the buildfarm green.Will look closer at an implementation which works across all supported versions
of OpenSSL when I have more time.
Finally had some time, and have made an updated version of the patch.
OpenSSL 1.0.2 doens't expose a function for getting the timestamp, so the patch
instead resorts to the older trick of getting the timestamp by inspecing the
diff against the UNIX epoch. When doing this, OpenSSL internally use the same
function which later in 1.1.1 was exported for getting the timestamp.
The attached version passes ssl tests for me on 1.0.2 through OpenSSL Git HEAD.
--
Daniel Gustafsson
Attachments:
v7-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patchapplication/octet-stream; name=v7-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patch; x-unix-mode=0644Download
From d7c3d3d32a61467065a4488ba184dbad1b7894ef Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Tue, 25 Jul 2023 15:28:21 +0200
Subject: [PATCH v7] 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. Patch by Cary Huang with some additional
hacking by me for supporting older OpenSSL versions.
Author: Cary Huang <cary.huang@highgo.ca>
Discussion: https://postgr.es/m/182b8565486.10af1a86f158715.2387262617218380588@highgo.ca
---
contrib/sslinfo/Makefile | 2 +-
contrib/sslinfo/meson.build | 1 +
contrib/sslinfo/sslinfo--1.2--1.3.sql | 12 ++++
contrib/sslinfo/sslinfo.c | 80 +++++++++++++++++++++
contrib/sslinfo/sslinfo.control | 2 +-
doc/src/sgml/monitoring.sgml | 20 ++++++
doc/src/sgml/sslinfo.sgml | 30 ++++++++
src/backend/catalog/system_views.sql | 4 +-
src/backend/libpq/be-secure-openssl.c | 58 +++++++++++++++
src/backend/utils/activity/backend_status.c | 2 +
src/backend/utils/adt/pgstatfuncs.c | 48 ++++++++-----
src/include/catalog/pg_proc.dat | 6 +-
src/include/libpq/libpq-be.h | 2 +
src/include/utils/backend_status.h | 3 +
src/test/regress/expected/rules.out | 12 ++--
src/test/ssl/t/001_ssltests.pl | 8 +--
src/test/ssl/t/003_sslinfo.pl | 14 ++++
17 files changed, 272 insertions(+), 32 deletions(-)
create mode 100644 contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..78a5a83d5c 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 999456d3a4..215b01daff 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..9d64d2bfa4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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 timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notbefore'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notafter() RETURNS timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..7d4109c751 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#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 +35,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_timestamp(ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -225,6 +227,52 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into timestamp
+ *
+ * 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 an 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_timestamp(ASN1_TIME *ASN1_cert_ts)
+{
+ int days;
+ int seconds;
+ const char utc_epoch[] = "19700101000000Z";
+ ASN1_TIME *ASN1_epoch;
+
+ /* 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 certificat timestamp */
+ if (!ASN1_TIME_set_string(ASN1_epoch, utc_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);
+
+ return DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum(((double)days * 24 * 60 * 60) + (double)seconds));
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +530,35 @@ ssl_extension_info(PG_FUNCTION_ARGS)
/* All done */
SRF_RETURN_DONE(funcctx);
}
+
+/*
+ * Returns current client certificate notBefore timestamp in
+ * timestamp 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_timestamp(X509_get_notBefore(cert));
+}
+
+/*
+ * Returns current client certificate notAfter timestamp in
+ * timestamp 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_timestamp(X509_get_notAfter(cert));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 588b720f57..42c7808f50 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2257,6 +2257,26 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
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 UTC 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 UTC timestamp of the client certificate, or NULL if no client
+ certificate was supplied.
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..06f5728096 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -240,6 +240,36 @@ emailAddress
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notbefore() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notbefore</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not before</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <function>ssl_client_get_notafter() returns text</function>
+ <indexterm>
+ <primary>ssl_client_get_notafter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Return the <structfield>not after</structfield> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index af65af6bdd..f7c2cfb8cd 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -970,7 +970,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 658b09988d..229d59895d 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -36,6 +36,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 +73,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 Timestamp ASN1_TIME_to_timestamp(ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool SSL_initialized = false;
@@ -1406,6 +1408,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, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notBefore(port->peer));
+ else
+ *ptr = 0;
+}
+
+void
+be_tls_get_peer_not_after(Port *port, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notAfter(port->peer));
+ else
+ *ptr = 0;
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1549,6 +1569,44 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a Timestamp. 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 an
+ * 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 Timestamp
+ASN1_TIME_to_timestamp(ASN1_TIME *ASN1_cert_ts)
+{
+ int days;
+ int seconds;
+ const char utc_epoch[] = "19700101000000Z";
+ ASN1_TIME *ASN1_epoch;
+
+ /* 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 certificat timestamp */
+ if (!ASN1_TIME_set_string(ASN1_epoch, utc_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);
+
+ return ((int64)days * 24 * 60 * 60) + (int64)seconds;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 38f91a495b..02dc9d7931 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -367,6 +367,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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 2a4c8ef87f..ba3da4e6bb 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -303,7 +303,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);
@@ -395,7 +395,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
pfree(clipped_activity);
/* leader_pid */
- nulls[29] = true;
+ nulls[31] = true;
proc = BackendPidGetProc(beentry->st_procpid);
@@ -432,8 +432,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)
{
@@ -441,8 +441,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;
}
}
}
@@ -587,35 +587,47 @@ 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] = DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum((double) beentry->st_sslstatus->ssl_not_before));
+ else
+ nulls[25] = true;
+
+ if (beentry->st_sslstatus->ssl_not_after != 0)
+ values[26] = DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum((double) 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
{
@@ -645,6 +657,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 6996073989..878c997e87 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5413,9 +5413,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,timestamp,timestamp,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 => '3318',
descr => 'statistics: information about progress of backends running maintenance command',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index a0b74c8095..02765ba9d9 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -298,6 +298,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, Timestamp *ptr);
+extern void be_tls_get_peer_not_after(Port *port, Timestamp *ptr);
/*
* Get the server certificate hash for SCRAM channel binding type
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 77939a0aed..ad6435d7da 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -61,6 +61,9 @@ typedef struct PgBackendSSLStatus
char ssl_client_serial[NAMEDATALEN];
char ssl_issuer_dn[NAMEDATALEN];
+ /* Certificate validity in unix epoch format */
+ Timestamp ssl_not_before;
+ Timestamp ssl_not_after;
} PgBackendSSLStatus;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index e07afcd4aa..30108846c1 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1760,7 +1760,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,
@@ -1878,7 +1878,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,
@@ -2080,7 +2080,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,
@@ -2113,8 +2113,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 76442de063..bad41cacc8 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -543,8 +543,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.
@@ -745,8 +745,8 @@ command_like(
'-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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E\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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E,\Q2023-06-29 01:01:01\E,\Q2050-01-01 01:01:01\E\r?$}mx,
'pg_stat_ssl with client certificate');
# client key with wrong permissions
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 5306aad802..f050a6f4f9 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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 = '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 = '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';",
--
2.32.1 (Apple Git-133)
Hello,
On 7/25/23 07:21, Daniel Gustafsson wrote:
The attached version passes ssl tests for me on 1.0.2 through OpenSSL Git HEAD.
Tests pass for me too, including LibreSSL 3.8.
+ /* Calculate the diff from the epoch to the certificat timestamp */
"certificate"
+ <function>ssl_client_get_notbefore() returns text</function>
...> + <function>ssl_client_get_notafter() returns text</function>
I think this should say timestamptz rather than text? Ditto for the
pg_stat_ssl documentation.
Speaking of which: is the use of `timestamp` rather than `timestamptz`
in pg_proc.dat intentional? Will that cause problems with comparisons?
--
I haven't been able to poke any holes in the ASN1_TIME_to_timestamp()
implementations themselves. I went down a rabbit hole trying to find out
whether leap seconds could cause problems for us when we switch to
`struct tm` in the future, but it turns out OpenSSL rejects leap seconds
in the Validity fields. That seems weird -- as far as I can tell, RFC
5280 defers to ASN.1 which defers to ISO 8601 which appears to allow
leap seconds -- but I don't plan to worry about it anymore. (I do idly
wonder whether some CA, somewhere, has ever had a really Unhappy New
Year due to that.)
Thanks,
--Jacob
On 12 Sep 2023, at 21:40, Jacob Champion <jchampion@timescale.com> wrote:
Hello,
On 7/25/23 07:21, Daniel Gustafsson wrote:
The attached version passes ssl tests for me on 1.0.2 through OpenSSL Git HEAD.
Tests pass for me too, including LibreSSL 3.8.
Thanks for testing!
+ /* Calculate the diff from the epoch to the certificat timestamp */
"certificate"
Fixed.
+ <function>ssl_client_get_notbefore() returns text</function>
...> + <function>ssl_client_get_notafter() returns text</function>I think this should say timestamptz rather than text? Ditto for the
pg_stat_ssl documentation.Speaking of which: is the use of `timestamp` rather than `timestamptz`
in pg_proc.dat intentional? Will that cause problems with comparisons?
It should be timestamptz, it was a tyop on my part. Fixed.
I haven't been able to poke any holes in the ASN1_TIME_to_timestamp()
implementations themselves. I went down a rabbit hole trying to find out
whether leap seconds could cause problems for us when we switch to
`struct tm` in the future, but it turns out OpenSSL rejects leap seconds
in the Validity fields. That seems weird -- as far as I can tell, RFC
5280 defers to ASN.1 which defers to ISO 8601 which appears to allow
leap seconds -- but I don't plan to worry about it anymore. (I do idly
wonder whether some CA, somewhere, has ever had a really Unhappy New
Year due to that.)
That's an interesting thought, maybe the CA's have adapted given the
marketshare of OpenSSL?
Thanks for reviewing, the attached v8 contains the fixes from this review along
with a fresh rebase and some attempts at making tests more stable in the face
of timezones by casting to date.
--
Daniel Gustafsson
Attachments:
v8-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patchapplication/octet-stream; name=v8-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patch; x-unix-mode=0644Download
From f5e59fb3bb491c609f40180fc2012e6afa694d2c Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Fri, 15 Sep 2023 15:28:50 +0200
Subject: [PATCH v8] 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. Patch by Cary Huang with some additional
hacking by me for supporting older OpenSSL versions.
Author: Cary Huang <cary.huang@highgo.ca>
Author: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Jacob Champion <jchampion@timescale.com>
Discussion: https://postgr.es/m/182b8565486.10af1a86f158715.2387262617218380588@highgo.ca
---
contrib/sslinfo/Makefile | 2 +-
contrib/sslinfo/meson.build | 1 +
contrib/sslinfo/sslinfo--1.2--1.3.sql | 12 ++++
contrib/sslinfo/sslinfo.c | 80 +++++++++++++++++++++
contrib/sslinfo/sslinfo.control | 2 +-
doc/src/sgml/monitoring.sgml | 20 ++++++
doc/src/sgml/sslinfo.sgml | 30 ++++++++
src/backend/catalog/system_views.sql | 4 +-
src/backend/libpq/be-secure-openssl.c | 58 +++++++++++++++
src/backend/utils/activity/backend_status.c | 2 +
src/backend/utils/adt/pgstatfuncs.c | 48 ++++++++-----
src/include/catalog/pg_proc.dat | 6 +-
src/include/libpq/libpq-be.h | 2 +
src/include/utils/backend_status.h | 3 +
src/test/regress/expected/rules.out | 12 ++--
src/test/ssl/t/001_ssltests.pl | 10 +--
src/test/ssl/t/003_sslinfo.pl | 14 ++++
17 files changed, 273 insertions(+), 33 deletions(-)
create mode 100644 contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..78a5a83d5c 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 999456d3a4..215b01daff 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..9d64d2bfa4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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 timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notbefore'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
+
+CREATE FUNCTION ssl_client_get_notafter() RETURNS timestamp
+AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
+LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..1017bc2ce6 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#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 +35,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_timestamp(ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -225,6 +227,52 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into timestamp
+ *
+ * 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 an 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_timestamp(ASN1_TIME *ASN1_cert_ts)
+{
+ int days;
+ int seconds;
+ const char utc_epoch[] = "19700101000000Z";
+ ASN1_TIME *ASN1_epoch;
+
+ /* 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, utc_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);
+
+ return DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum(((double)days * 24 * 60 * 60) + (double)seconds));
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +530,35 @@ ssl_extension_info(PG_FUNCTION_ARGS)
/* All done */
SRF_RETURN_DONE(funcctx);
}
+
+/*
+ * Returns current client certificate notBefore timestamp in
+ * timestamp 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_timestamp(X509_get_notBefore(cert));
+}
+
+/*
+ * Returns current client certificate notAfter timestamp in
+ * timestamp 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_timestamp(X509_get_notAfter(cert));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 4ff415d6a0..c6312c08a2 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2271,6 +2271,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 UTC 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 UTC timestamp of the client certificate, or NULL if no client
+ certificate was supplied.
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..221d562046 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -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> UTC 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> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 77b06e2a7a..e7be7c1c90 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -970,7 +970,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 658b09988d..40e2d943ae 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -36,6 +36,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 +73,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 Timestamp ASN1_TIME_to_timestamp(ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool SSL_initialized = false;
@@ -1406,6 +1408,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, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notBefore(port->peer));
+ else
+ *ptr = 0;
+}
+
+void
+be_tls_get_peer_not_after(Port *port, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notAfter(port->peer));
+ else
+ *ptr = 0;
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1549,6 +1569,44 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a Timestamp. 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 an
+ * 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 Timestamp
+ASN1_TIME_to_timestamp(ASN1_TIME *ASN1_cert_ts)
+{
+ int days;
+ int seconds;
+ const char utc_epoch[] = "19700101000000Z";
+ ASN1_TIME *ASN1_epoch;
+
+ /* 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, utc_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);
+
+ return ((int64)days * 24 * 60 * 60) + (int64)seconds;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 722c5acf38..91b052ef05 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -367,6 +367,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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index dd5094a2d4..d5b070fc2b 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -304,7 +304,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);
@@ -396,7 +396,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
pfree(clipped_activity);
/* leader_pid */
- nulls[29] = true;
+ nulls[31] = true;
proc = BackendPidGetProc(beentry->st_procpid);
@@ -433,8 +433,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)
{
@@ -442,8 +442,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;
}
}
}
@@ -588,35 +588,47 @@ 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] = DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum((double) beentry->st_sslstatus->ssl_not_before));
+ else
+ nulls[25] = true;
+
+ if (beentry->st_sslstatus->ssl_not_after != 0)
+ values[26] = DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum((double) 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
{
@@ -646,6 +658,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 9805bc6118..786c21b0b7 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5425,9 +5425,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',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index a0b74c8095..02765ba9d9 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -298,6 +298,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, Timestamp *ptr);
+extern void be_tls_get_peer_not_after(Port *port, Timestamp *ptr);
/*
* Get the server certificate hash for SCRAM channel binding type
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index d51c840daf..35789c5500 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -61,6 +61,9 @@ typedef struct PgBackendSSLStatus
char ssl_client_serial[NAMEDATALEN];
char ssl_issuer_dn[NAMEDATALEN];
+ /* Certificate validity in unix epoch format */
+ Timestamp ssl_not_before;
+ Timestamp ssl_not_after;
} PgBackendSSLStatus;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 5058be5411..d77760fdac 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1760,7 +1760,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,
@@ -1878,7 +1878,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,
@@ -2080,7 +2080,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,
@@ -2113,8 +2113,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 23248d71b0..7448932a78 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -543,8 +543,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.
@@ -743,10 +743,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::date,not_after::date 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,2050-01-01\E\r?$}mx,
'pg_stat_ssl with client certificate');
# client key with wrong permissions
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 5306aad802..123dddcb2b 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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()::date = not_before::date, "
+ . "not_before::date = '2023-06-29' 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()::date = not_after::date, "
+ . "not_after::date = '2050-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';",
--
2.32.1 (Apple Git-133)
On Mon, Mar 4, 2024 at 6:23 AM Daniel Gustafsson <daniel@yesql.se> wrote:
On 12 Sep 2023, at 21:40, Jacob Champion <jchampion@timescale.com> wrote:
Sorry for the long delay!
+ <function>ssl_client_get_notbefore() returns text</function>
...> + <function>ssl_client_get_notafter() returns text</function>I think this should say timestamptz rather than text? Ditto for the
pg_stat_ssl documentation.Speaking of which: is the use of `timestamp` rather than `timestamptz`
in pg_proc.dat intentional? Will that cause problems with comparisons?It should be timestamptz, it was a tyop on my part. Fixed.
Looks like sslinfo--1.2--1.3.sql is also declaring the functions as
timestamp rather than timestamptz, which is breaking comparisons with
the not_before/after columns. It might also be nice to rename
ASN1_TIME_to_timestamp().
Squinting further at the server backend implementation, should that
also be using TimestampTz throughout, instead of Timestamp? It all
goes through float8_timestamptz at the end, so I guess it shouldn't
have a material impact, but it's a bit confusing.
Thanks for reviewing, the attached v8 contains the fixes from this review along
with a fresh rebase and some attempts at making tests more stable in the face
of timezones by casting to date.
In my -08 timezone, the date doesn't match what's recorded either
(it's my "tomorrow"). I think those probably just need to be converted
to UTC explicitly? I've attached a sample diff on top of v8 that
passes tests on my machine.
--Jacob
Attachments:
timestamptz.diff.txttext/plain; charset=US-ASCII; name=timestamptz.diff.txtDownload
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
index 9d64d2bfa4..424a11afe4 100644
--- a/contrib/sslinfo/sslinfo--1.2--1.3.sql
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -3,10 +3,10 @@
-- complain if 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 timestamp
+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 timestamp
+CREATE FUNCTION ssl_client_get_notafter() RETURNS timestamptz
AS 'MODULE_PATHNAME', 'ssl_client_get_notafter'
LANGUAGE C STRICT PARALLEL RESTRICTED;
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 490c48a7bb..90a4230413 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -740,10 +740,10 @@ command_like(
"$common_connstr user=ssltestuser sslcert=ssl/client.crt "
. sslkey('client.key'),
'-c',
- "SELECT ssl,version,cipher,bits,client_dn,client_serial,issuer_dn,not_before::date,not_after::date 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{^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,2050-01-01\E\r?$}mx,
+ ^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
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 587c0e2dce..4df3a941b5 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -167,15 +167,15 @@ is($result, 't', "ssl_issuer_field() for commonName");
$result = $node->safe_psql(
"certdb",
- "SELECT ssl_client_get_notbefore()::date = not_before::date, "
- . "not_before::date = '2023-06-29' FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
+ "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()::date = not_after::date, "
- . "not_after::date = '2050-01-01' FROM pg_stat_ssl WHERE pid = pg_backend_pid();",
+ "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");
Hello
Thank you for the review and your patch. I have tested with minimum OpenSSL version 1.0.2 support and incorporated your changes into the v9 patch as attached.
In my -08 timezone, the date doesn't match what's recorded either
(it's my "tomorrow"). I think those probably just need to be converted
to UTC explicitly? I've attached a sample diff on top of v8 that
passes tests on my machine.
Yes, I noticed this in the SSL test too. I am also in GTM-8, so for me the tests would fail too due to the time zone differences from GMT. It shall be okay to specifically set the outputs of pg_stat_ssl, ssl_client_get_notbefore, and ssl_client_get_notafte to be in GMT time zone. The not before and not after time stamps in a client certificate are generally expressed in GMT.
Thank you!
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
Attachments:
v9-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patchapplication/octet-stream; name=v9-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patchDownload
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..78a5a83d5c 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 39d49a1736..a4bcd21ea6 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..424a11afe4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..1017bc2ce6 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#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 +35,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_timestamp(ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -225,6 +227,52 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into timestamp
+ *
+ * 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 an 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_timestamp(ASN1_TIME *ASN1_cert_ts)
+{
+ int days;
+ int seconds;
+ const char utc_epoch[] = "19700101000000Z";
+ ASN1_TIME *ASN1_epoch;
+
+ /* 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, utc_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);
+
+ return DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum(((double)days * 24 * 60 * 60) + (double)seconds));
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +530,35 @@ ssl_extension_info(PG_FUNCTION_ARGS)
/* All done */
SRF_RETURN_DONE(funcctx);
}
+
+/*
+ * Returns current client certificate notBefore timestamp in
+ * timestamp 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_timestamp(X509_get_notBefore(cert));
+}
+
+/*
+ * Returns current client certificate notAfter timestamp in
+ * timestamp 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_timestamp(X509_get_notAfter(cert));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8aca08140e..029602262a 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -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 UTC 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 UTC timestamp of the client certificate, or NULL if no client
+ certificate was supplied.
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..221d562046 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -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> UTC 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> UTC timestamp of the client
+ certificate.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 04227a72d1..9d778794d4 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 72e43af353..decbb29d67 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -36,6 +36,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 +73,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 Timestamp ASN1_TIME_to_timestamp(ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool SSL_initialized = false;
@@ -1430,6 +1432,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, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notBefore(port->peer));
+ else
+ *ptr = 0;
+}
+
+void
+be_tls_get_peer_not_after(Port *port, Timestamp *ptr)
+{
+ if (port->peer)
+ *ptr = ASN1_TIME_to_timestamp(X509_get_notAfter(port->peer));
+ else
+ *ptr = 0;
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1573,6 +1593,44 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a Timestamp. 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 an
+ * 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 Timestamp
+ASN1_TIME_to_timestamp(ASN1_TIME *ASN1_cert_ts)
+{
+ int days;
+ int seconds;
+ const char utc_epoch[] = "19700101000000Z";
+ ASN1_TIME *ASN1_epoch;
+
+ /* 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, utc_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);
+
+ return ((int64)days * 24 * 60 * 60) + (int64)seconds;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 1ccf4c6d83..121ec8956f 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 3876339ee1..13e5a8150b 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -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,47 @@ 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] = DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum((double) beentry->st_sslstatus->ssl_not_before));
+ else
+ nulls[25] = true;
+
+ if (beentry->st_sslstatus->ssl_not_after != 0)
+ values[26] = DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum((double) 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 +656,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 291ed876fc..97a2a429e5 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -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',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 47d66d5524..e9246d6187 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -298,6 +298,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, Timestamp *ptr);
+extern void be_tls_get_peer_not_after(Port *port, Timestamp *ptr);
/*
* Get the server certificate hash for SCRAM channel binding type
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 7b7f6f59d0..42017dcbff 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -61,6 +61,9 @@ typedef struct PgBackendSSLStatus
char ssl_client_serial[NAMEDATALEN];
char ssl_issuer_dn[NAMEDATALEN];
+ /* Certificate validity in unix epoch format */
+ Timestamp ssl_not_before;
+ Timestamp ssl_not_after;
} PgBackendSSLStatus;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 0cd2c64fca..9718e2a88a 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1762,7 +1762,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,
@@ -1882,7 +1882,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,
@@ -2085,7 +2085,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,
@@ -2118,8 +2118,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 94ff043c8e..90a4230413 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -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
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 2ae5724846..4df3a941b5 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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';",
On Fri, Mar 8, 2024 at 4:16 PM Cary Huang <cary.huang@highgo.ca> wrote:
Yes, I noticed this in the SSL test too. I am also in GTM-8, so for me the tests would fail too due to the time zone differences from GMT. It shall be okay to specifically set the outputs of pg_stat_ssl, ssl_client_get_notbefore, and ssl_client_get_notafte to be in GMT time zone. The not before and not after time stamps in a client certificate are generally expressed in GMT.
Hi Cary, did you have any thoughts on the timestamptz notes from my last mail?
It might also be nice to rename
ASN1_TIME_to_timestamp().Squinting further at the server backend implementation, should that
also be using TimestampTz throughout, instead of Timestamp? It all
goes through float8_timestamptz at the end, so I guess it shouldn't
have a material impact, but it's a bit confusing.
Thanks,
--Jacob
Hi Jacob
Hi Cary, did you have any thoughts on the timestamptz notes from my last mail?
It might also be nice to rename
ASN1_TIME_to_timestamp().Squinting further at the server backend implementation, should that
also be using TimestampTz throughout, instead of Timestamp? It all
goes through float8_timestamptz at the end, so I guess it shouldn't
have a material impact, but it's a bit confusing.
Sorry I kind of missed this review comment from your last email. Thanks for bringing it up again though. I think it is right to change the backend references of "timestamp" to "timestampTz" for consistency reasons. I have gone ahead to make the changes.
I have also reviewed the wording on the documentation and removed "UTC" from the descriptions. Since sslinfo extension and pg_stat_ssl both return timestampTz in whatever timezone PostgreSQL is running on, they do not always return UTC timestamps.
Attached is the v10 patch with the above changes. Thanks again for the review.
Best regards
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
Attachments:
v10-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patchapplication/octet-stream; name=v10-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-displ.patchDownload
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..78a5a83d5c 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 39d49a1736..a4bcd21ea6 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..424a11afe4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..b05287147a 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#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 +35,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 +227,52 @@ 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 utc_epoch[] = "19700101000000Z";
+ ASN1_TIME *ASN1_epoch;
+
+ /* 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, utc_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);
+
+ return DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum(((double)days * 24 * 60 * 60) + (double)seconds));
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +530,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));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8736eac284..ca6b5631d7 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -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>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..2a6725cc1c 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -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>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 04227a72d1..9d778794d4 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 72e43af353..9163dffd49 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -36,6 +36,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 +73,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 +1432,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 +1593,44 @@ 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 utc_epoch[] = "19700101000000Z";
+ ASN1_TIME *ASN1_epoch;
+
+ /* 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, utc_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);
+
+ return ((int64)days * 24 * 60 * 60) + (int64)seconds;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 1ccf4c6d83..121ec8956f 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 3876339ee1..13e5a8150b 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -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,47 @@ 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] = DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum((double) beentry->st_sslstatus->ssl_not_before));
+ else
+ nulls[25] = true;
+
+ if (beentry->st_sslstatus->ssl_not_after != 0)
+ values[26] = DirectFunctionCall1(float8_timestamptz,
+ Float8GetDatum((double) 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 +656,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 700f7daf7b..6e9930a4d2 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -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',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 4dce767751..3414899ebf 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -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
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 7b7f6f59d0..4fa8ff5888 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -61,6 +61,9 @@ typedef struct PgBackendSSLStatus
char ssl_client_serial[NAMEDATALEN];
char ssl_issuer_dn[NAMEDATALEN];
+ /* Certificate validity in unix epoch format */
+ TimestampTz ssl_not_before;
+ TimestampTz ssl_not_after;
} PgBackendSSLStatus;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 84e359f6ed..ed7574781c 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1762,7 +1762,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,
@@ -1882,7 +1882,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,
@@ -2085,7 +2085,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,
@@ -2118,8 +2118,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 94ff043c8e..90a4230413 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -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
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 2ae5724846..4df3a941b5 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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';",
On Mon, Mar 18, 2024 at 1:48 PM Cary Huang <cary.huang@highgo.ca> wrote:
Attached is the v10 patch with the above changes. Thanks again for the review.
Awesome, looks good.
On my final review pass I saw one last thing that bothered me (sorry
for not seeing it before). The backend version of
ASN1_TIME_to_timestamptz returns the following:
+ return ((int64)days * 24 * 60 * 60) + (int64)seconds;
...but I think Timestamp[Tz]s are stored as microseconds, so we're off
by a factor of a million. This still works because later we cast to
double and pass it back through float8_timestamptz, which converts it:
+ if (beentry->st_sslstatus->ssl_not_before != 0) + values[25] = DirectFunctionCall1(float8_timestamptz, + Float8GetDatum((double) beentry->st_sslstatus->ssl_not_before));
But anyone who ends up inspecting the value of
st_sslstatus->ssl_not_before directly is going to find an incorrect
timestamp. I think it'd be clearer to store microseconds to begin
with, and then just use TimestampTzGetDatum rather than the
DirectFunctionCall1 we have now. (I looked for an existing
implementation to reuse and didn't find one. Maybe we should use the
overflow-aware multiplication/addition routines -- i.e.
pg_mul_s64_overflow et al -- to multiply `days` and `seconds` by
USECS_PER_DAY/USECS_PER_SEC and combine them.)
And I think sslinfo can remain as-is, because that way overflow is
caught by float8_timestamptz. WDYT?
--Jacob
Thank you for your review again.
...but I think Timestamp[Tz]s are stored as microseconds, so we're off
by a factor of a million. This still works because later we cast to
double and pass it back through float8_timestamptz, which converts it:
In my test, if I made ASN1_TIME_to_timestamptz to return in microseconds, the
float8_timestamptz() function will catch a "timestamp out of range" exception as
this function treats the input as seconds.
But anyone who ends up inspecting the value of
st_sslstatus->ssl_not_before directly is going to find an incorrect
timestamp. I think it'd be clearer to store microseconds to begin
with, and then just use TimestampTzGetDatum rather than the
DirectFunctionCall1 we have now.
I have also tried TimestampTzGetDatum with ASN1_TIME_to_timestamptz
outputting in microseconds. No exception is caught, but pg_stat_ssl displays
incorrect results. The timestamps are extra large because the extra factor of
1 million is considered in the timestamp computation as well.
The comments for TimestampTz says:
* Timestamps, as well as the h/m/s fields of intervals, are stored as
* int64 values with units of microseconds. (Once upon a time they were
* double values with units of seconds.)
but it seems to me that many of the timestamp related functions still consider
timestamp or timestampTz as "double values with units of seconds" though.
Best regards
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
On 20 Mar 2024, at 00:24, Cary Huang <cary.huang@highgo.ca> wrote:
but it seems to me that many of the timestamp related functions still consider
timestamp or timestampTz as "double values with units of seconds" though.
The issue here is that postgres use a different epoch from the unix epoch, so
any dates calcuated based on the unix epoch need to be adjusted. I've hacked
this up in the attached v11 using overflow-safe integer mul/add as proposed by
Jacob upthread (we really shouldn't risk overflowing an int64 here but there is
no harm in using belts and suspenders here as a defensive measure).
The attached v11 is what I propose we go ahead with unless there further
comments on this.
--
Daniel Gustafsson
Attachments:
v11-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patchapplication/octet-stream; name=v11-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patch; x-unix-mode=0644Download
From 1d8d7be0a9c6e6a945c1cb4b40daac7e53014aeb Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Wed, 20 Mar 2024 14:55:52 +0100
Subject: [PATCH v11] 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
---
contrib/sslinfo/Makefile | 2 +-
contrib/sslinfo/meson.build | 1 +
contrib/sslinfo/sslinfo--1.2--1.3.sql | 12 +++
contrib/sslinfo/sslinfo.c | 96 +++++++++++++++++++++
contrib/sslinfo/sslinfo.control | 2 +-
doc/src/sgml/monitoring.sgml | 20 +++++
doc/src/sgml/sslinfo.sgml | 30 +++++++
src/backend/catalog/system_views.sql | 4 +-
src/backend/libpq/be-secure-openssl.c | 84 ++++++++++++++++++
src/backend/utils/activity/backend_status.c | 2 +
src/backend/utils/adt/pgstatfuncs.c | 46 ++++++----
src/include/catalog/pg_proc.dat | 6 +-
src/include/libpq/libpq-be.h | 2 +
src/include/utils/backend_status.h | 3 +
src/test/regress/expected/rules.out | 12 +--
src/test/ssl/t/001_ssltests.pl | 10 +--
src/test/ssl/t/003_sslinfo.pl | 14 +++
17 files changed, 313 insertions(+), 33 deletions(-)
create mode 100644 contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..78a5a83d5c 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 39d49a1736..a4bcd21ea6 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..424a11afe4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..6be56f8103 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -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,67 @@ 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 utc_epoch[] = "19700101000000Z";
+ 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, utc_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);
+ }
+
+ result -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY);
+ return TimestampTzGetDatum(result);
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +546,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));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8736eac284..ca6b5631d7 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -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>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..2a6725cc1c 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -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>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 04227a72d1..9d778794d4 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 72e43af353..4a24532c27 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -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,69 @@ 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 utc_epoch[] = "19700101000000Z";
+ 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. Can't
+ * use UNIX_EPOCH_JDATE here since OpenSSL needs an epoch in the ASN.1
+ * format
+ */
+ if (!ASN1_TIME_set_string(ASN1_epoch, utc_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;
+ }
+
+ /*
+ * The result must be adjusted for the Postgres epoch which is different
+ * from the UNIX epoch.
+ */
+ result -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY);
+
+ return result;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 1ccf4c6d83..121ec8956f 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 3876339ee1..61522642cb 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 177d81a891..c6d98b5ee1 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -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',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 4dce767751..3414899ebf 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -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
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 7b7f6f59d0..d5bd4eceb6 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -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;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 84e359f6ed..ed7574781c 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1762,7 +1762,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,
@@ -1882,7 +1882,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,
@@ -2085,7 +2085,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,
@@ -2118,8 +2118,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 94ff043c8e..90a4230413 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -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
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 2ae5724846..4df3a941b5 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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';",
--
2.32.1 (Apple Git-133)
On Wed, Mar 20, 2024 at 7:03 AM Daniel Gustafsson <daniel@yesql.se> wrote:
The issue here is that postgres use a different epoch from the unix epoch, so
any dates calcuated based on the unix epoch need to be adjusted.
Ah, thank you! I had just reproduced Cary's problem and was really confused...
I've hacked
this up in the attached v11 using overflow-safe integer mul/add as proposed by
Jacob upthread (we really shouldn't risk overflowing an int64 here but there is
no harm in using belts and suspenders here as a defensive measure).The attached v11 is what I propose we go ahead with unless there further
comments on this.
One last question:
+ result -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY); + return TimestampTzGetDatum(result);
Is that final bare subtraction able to wrap around for dates far in the past?
--Jacob
On 20 Mar 2024, at 15:28, Jacob Champion <jacob.champion@enterprisedb.com> wrote:
+ result -= ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY); + return TimestampTzGetDatum(result);Is that final bare subtraction able to wrap around for dates far in the past?
We are subtracting 30 years from a calculation that we know didnt overflow, so
I guess if the certificate notBefore (the notAfter cannot be that early since
we wouldn't be able to connect with it) was set to early enough? It didn't
strike me as anything above academical unless I'm thinking wrong here.
--
Daniel Gustafsson
On Wed, Mar 20, 2024 at 7:50 AM Daniel Gustafsson <daniel@yesql.se> wrote:
We are subtracting 30 years from a calculation that we know didnt overflow, so
I guess if the certificate notBefore (the notAfter cannot be that early since
we wouldn't be able to connect with it) was set to early enough? It didn't
strike me as anything above academical unless I'm thinking wrong here.
Yeah, it's super nitpicky. The CA would have had to sign a really
broken certificate somehow, anyway...
I can't find anything else to note; patch LGTM.
Thanks,
--Jacob
On 20 Mar 2024, at 17:32, Jacob Champion <jacob.champion@enterprisedb.com> wrote:
I can't find anything else to note; patch LGTM.
While staging this to commit I realized one silly thing about it warranting
another round here. The ASN.1 timediff code can diff against *any* timestamp,
not just the UNIX epoch, so we could just pass in the postgres epoch and skip
the final subtraction since we're already correctly adjusted. This removes the
non-overflow checked arithmetic with a simpler logic.
--
Daniel Gustafsson
Attachments:
v12-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patchapplication/octet-stream; name=v12-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patch; x-unix-mode=0644Download
From c3c01b32d480753d5652226d2785964f9fa22575 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Fri, 22 Mar 2024 10:58:48 +0100
Subject: [PATCH v12] 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
---
contrib/sslinfo/Makefile | 2 +-
contrib/sslinfo/meson.build | 1 +
contrib/sslinfo/sslinfo--1.2--1.3.sql | 12 +++
contrib/sslinfo/sslinfo.c | 95 +++++++++++++++++++++
contrib/sslinfo/sslinfo.control | 2 +-
doc/src/sgml/monitoring.sgml | 20 +++++
doc/src/sgml/sslinfo.sgml | 30 +++++++
src/backend/catalog/system_views.sql | 4 +-
src/backend/libpq/be-secure-openssl.c | 78 +++++++++++++++++
src/backend/utils/activity/backend_status.c | 2 +
src/backend/utils/adt/pgstatfuncs.c | 46 ++++++----
src/include/catalog/pg_proc.dat | 6 +-
src/include/libpq/libpq-be.h | 2 +
src/include/utils/backend_status.h | 3 +
src/test/regress/expected/rules.out | 12 +--
src/test/ssl/t/001_ssltests.pl | 10 +--
src/test/ssl/t/003_sslinfo.pl | 14 +++
17 files changed, 306 insertions(+), 33 deletions(-)
create mode 100644 contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..78a5a83d5c 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 39d49a1736..a4bcd21ea6 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..424a11afe4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..904b203a17 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -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));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8736eac284..ca6b5631d7 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -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>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..2a6725cc1c 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -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>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index f69b7f5580..72d5caa535 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 72e43af353..c6cc681b2e 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -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
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 1ccf4c6d83..121ec8956f 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 3876339ee1..61522642cb 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 71c74350a0..ea45b300b8 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -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',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 4dce767751..3414899ebf 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -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
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 7b7f6f59d0..d5bd4eceb6 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -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;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 18829ea586..037e83b2ad 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 94ff043c8e..90a4230413 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -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
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 2ae5724846..4df3a941b5 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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';",
--
2.32.1 (Apple Git-133)
On Fri, Mar 22, 2024 at 6:15 AM Daniel Gustafsson <daniel@yesql.se> wrote:
While staging this to commit I realized one silly thing about it warranting
another round here. The ASN.1 timediff code can diff against *any* timestamp,
not just the UNIX epoch, so we could just pass in the postgres epoch and skip
the final subtraction since we're already correctly adjusted. This removes the
non-overflow checked arithmetic with a simpler logic.
Ah, that's much better! +1.
--Jacob
The recent bump in minmum required versions of OpenSSL and LibreSSL made me
remember to revisit this patch which was previously reverted due to library
incompatibility (with *both* OpenSSL and LibreSSL on different APIs).
The attached removes the timestamp conversion workaround which is no longer
needed.
--
Daniel Gustafsson
Attachments:
v13-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patchapplication/octet-stream; name=v13-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patch; x-unix-mode=0644Download
From 2733c9f825e1a113d91e676a026156dded1047f6 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Mon, 28 Oct 2024 09:39:17 +0100
Subject: [PATCH v13] 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. This has been previously committed and
reverted due to SSL library compatibility issues which have since been
resolved due to raising the minimum required version.
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
---
contrib/sslinfo/Makefile | 2 +-
contrib/sslinfo/meson.build | 1 +
contrib/sslinfo/sslinfo--1.2--1.3.sql | 12 ++++
contrib/sslinfo/sslinfo.c | 71 +++++++++++++++++++++
contrib/sslinfo/sslinfo.control | 2 +-
doc/src/sgml/monitoring.sgml | 20 ++++++
doc/src/sgml/sslinfo.sgml | 30 +++++++++
src/backend/catalog/system_views.sql | 4 +-
src/backend/libpq/be-secure-openssl.c | 52 +++++++++++++++
src/backend/utils/activity/backend_status.c | 2 +
src/backend/utils/adt/pgstatfuncs.c | 46 ++++++++-----
src/include/catalog/pg_proc.dat | 6 +-
src/include/libpq/libpq-be.h | 2 +
src/include/utils/backend_status.h | 3 +
src/test/regress/expected/rules.out | 12 ++--
src/test/ssl/t/001_ssltests.pl | 10 +--
src/test/ssl/t/003_sslinfo.pl | 14 ++++
17 files changed, 256 insertions(+), 33 deletions(-)
create mode 100644 contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index dd1ff83b16..78a5a83d5c 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 39d49a1736..a4bcd21ea6 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..424a11afe4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..cad275b4d2 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#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 +35,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 +227,43 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into timestamptz
+ *
+ * Parameter: ASN1_TIME timestamp from certificate
+ *
+ * Returns the ASN1_TIME timestamp as a timestamptz datum.
+ */
+static Datum
+ASN1_TIME_to_timestamptz(ASN1_TIME *ASN1_cert_ts)
+{
+ struct pg_tm pgtm;
+ struct tm tm;
+ int ret;
+ Timestamp ts;
+
+ ret = ASN1_TIME_to_tm(ASN1_cert_ts, &tm);
+ if (!ret)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("failed to parse certificate validity")));
+
+ pgtm.tm_sec = tm.tm_sec;
+ pgtm.tm_min = tm.tm_min;
+ pgtm.tm_hour = tm.tm_hour;
+ pgtm.tm_mday = tm.tm_mday;
+ pgtm.tm_mon = tm.tm_mon + 1;
+ pgtm.tm_year = tm.tm_year + 1900;
+
+ if (unlikely(tm2timestamp(&pgtm, 0, NULL, &ts) != 0))
+ ereport(ERROR,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("timestamp out of range"));
+
+ PG_RETURN_TIMESTAMP(ts);
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +521,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));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 331315f8d3..e28d8ecbd7 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2373,6 +2373,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>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..2a6725cc1c 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -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>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 3456b821bc..20c3c36c40 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -985,7 +985,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 469be36e76..781a4f99a3 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -36,6 +36,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.
@@ -80,6 +81,7 @@ static const char *SSLerrmessageExt(unsigned long ecode, const char *replacement
static const char *SSLerrmessage(unsigned long ecode);
static char *X509_NAME_to_cstring(X509_NAME *name);
+static TimestampTz ASN1_TIME_to_timestamptz(ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool dummy_ssl_passwd_cb_called = false;
@@ -1558,6 +1560,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)
{
@@ -1701,6 +1721,38 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a PostgreSQL Timestamp datum.
+ */
+static TimestampTz
+ASN1_TIME_to_timestamptz(ASN1_TIME *ASN1_cert_ts)
+{
+ struct pg_tm pgtm;
+ struct tm tm;
+ int ret;
+ TimestampTz ts;
+
+ ret = ASN1_TIME_to_tm(ASN1_cert_ts, &tm);
+ if (!ret)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("failed to parse certificate validity")));
+
+ pgtm.tm_sec = tm.tm_sec;
+ pgtm.tm_min = tm.tm_min;
+ pgtm.tm_hour = tm.tm_hour;
+ pgtm.tm_mday = tm.tm_mday;
+ pgtm.tm_mon = tm.tm_mon + 1;
+ pgtm.tm_year = tm.tm_year + 1900;
+
+ if (unlikely(tm2timestamp(&pgtm, 0, NULL, &ts) != 0))
+ ereport(ERROR,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("timestamp out of range"));
+
+ return ts;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 34a55e2177..a820049be8 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -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
{
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index f7b50e0b5a..db09d1b1b7 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 1ec0d6f6b5..09b7623ac5 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5546,9 +5546,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 => '6318', descr => 'describe wait events',
proname => 'pg_get_wait_events', procost => '10', prorows => '250',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index d97d1e5f6b..8b74b45583 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -309,6 +309,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
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 97874300c3..1b14a3464f 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -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;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 2b47013f11..c382619205 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1762,7 +1762,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,
@@ -1884,7 +1884,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,
@@ -2088,7 +2088,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,
@@ -2121,8 +2121,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 131460a1fe..0f19db3e63 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -550,8 +550,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.
@@ -752,10 +752,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
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index b6cfa5d0b0..9f979ce3bf 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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';",
--
2.39.3 (Apple Git-146)
On Mon, Oct 28, 2024 at 09:59:35AM +0100, Daniel Gustafsson wrote:
The recent bump in minmum required versions of OpenSSL and LibreSSL made me
remember to revisit this patch which was previously reverted due to library
incompatibility (with *both* OpenSSL and LibreSSL on different APIs).The attached removes the timestamp conversion workaround which is no longer
needed.
The patch was marked as ready for committer and is currently failing
in the CI. I've moved it to next CF waiting on author. Could you
provide a rebase?
--
Michael
The recent bump in minmum required versions of OpenSSL and LibreSSL made me
remember to revisit this patch which was previously reverted due to library
incompatibility (with *both* OpenSSL and LibreSSL on different APIs).The attached removes the timestamp conversion workaround which is no longer
needed.The patch was marked as ready for committer and is currently failing
in the CI. I've moved it to next CF waiting on author. Could you
provide a rebase?
Since the minimum OpenSSL version is now 1.1.1, the v13 patch would fail the CI because
it uses the old APIs to obtain notBefore and notAfter timestamps:
- X509_get_notBefore
- X509_get_notAfter
which where deprecated in OpenSSL 1.1.0...
Instead, it should use:
- X509_get0_notBefore
- X509_get0_notAfter
which are available in version 1.1.1 and beyond. These APIs now return a "const ASN1_TIME*"
instead of "ASN1_TIME*".
The changes below should remove the CI failing when applied to v13 patch:
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
-static Datum ASN1_TIME_to_timestamptz(ASN1_TIME *time);
+static Datum ASN1_TIME_to_timestamptz(const ASN1_TIME *time);
-ASN1_TIME_to_timestamptz(ASN1_TIME *ASN1_cert_ts)
+ASN1_TIME_to_timestamptz(const ASN1_TIME *ASN1_cert_ts)
- return ASN1_TIME_to_timestamptz(X509_get_notBefore(cert));
+ return ASN1_TIME_to_timestamptz(X509_get0_notBefore(cert));
- return ASN1_TIME_to_timestamptz(X509_get_notAfter(cert));
+ return ASN1_TIME_to_timestamptz(X509_get0_notAfter(cert));
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
-static TimestampTz ASN1_TIME_to_timestamptz(ASN1_TIME *time);
+static TimestampTz ASN1_TIME_to_timestamptz(const ASN1_TIME *time);
-ASN1_TIME_to_timestamptz(ASN1_TIME *ASN1_cert_ts)
+ASN1_TIME_to_timestamptz(const ASN1_TIME *ASN1_cert_ts)
- *ptr = ASN1_TIME_to_timestamptz(X509_get_notBefore(port->peer));
+ *ptr = ASN1_TIME_to_timestamptz(X509_get0_notBefore(port->peer));
- *ptr = ASN1_TIME_to_timestamptz(X509_get_notAfter(port->peer));
+ *ptr = ASN1_TIME_to_timestamptz(X509_get0_notAfter(port->peer));
can you make a rebase with the above changes?
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
The attached v14 is the rebased patch that updated the OpenSSL API calls to be compatible in
version 1.1.1 (and beyond), which is the new minimum OpenSSL version supported in PostgreSQL.
Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
Attachments:
v14-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patchapplication/octet-stream; name=v14-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patchDownload
From e20848b277b69b2223c8e34425d1fbe6c51e14b3 Mon Sep 17 00:00:00 2001
From: Cary Huang <cary.huang@highgo.ca>
Date: Mon, 10 Mar 2025 11:32:11 -0700
Subject: [PATCH] rebased the patch and updated OpenSSL API calls to be
compatible in versions 1.1.1 and later
---
contrib/sslinfo/Makefile | 2 +-
contrib/sslinfo/meson.build | 1 +
contrib/sslinfo/sslinfo--1.2--1.3.sql | 12 ++++
contrib/sslinfo/sslinfo.c | 71 +++++++++++++++++++++
contrib/sslinfo/sslinfo.control | 2 +-
doc/src/sgml/monitoring.sgml | 20 ++++++
doc/src/sgml/sslinfo.sgml | 30 +++++++++
src/backend/catalog/system_views.sql | 4 +-
src/backend/libpq/be-secure-openssl.c | 52 +++++++++++++++
src/backend/utils/activity/backend_status.c | 2 +
src/backend/utils/adt/pgstatfuncs.c | 46 ++++++++-----
src/include/catalog/pg_proc.dat | 6 +-
src/include/libpq/libpq-be.h | 2 +
src/include/utils/backend_status.h | 3 +
src/test/regress/expected/rules.out | 12 ++--
src/test/ssl/t/001_ssltests.pl | 8 +--
src/test/ssl/t/003_sslinfo.pl | 14 ++++
17 files changed, 255 insertions(+), 32 deletions(-)
create mode 100644 contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index 14305594e2..ef1475fffb 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 4c51375920..b560da0820 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..424a11afe4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index 5fd46b9874..2688287672 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#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 +35,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(const ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -225,6 +227,43 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into timestamptz
+ *
+ * Parameter: ASN1_TIME timestamp from certificate
+ *
+ * Returns the ASN1_TIME timestamp as a timestamptz datum.
+ */
+static Datum
+ASN1_TIME_to_timestamptz(const ASN1_TIME *ASN1_cert_ts)
+{
+ struct pg_tm pgtm;
+ struct tm tm;
+ int ret;
+ Timestamp ts;
+
+ ret = ASN1_TIME_to_tm(ASN1_cert_ts, &tm);
+ if (!ret)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("failed to parse certificate validity")));
+
+ pgtm.tm_sec = tm.tm_sec;
+ pgtm.tm_min = tm.tm_min;
+ pgtm.tm_hour = tm.tm_hour;
+ pgtm.tm_mday = tm.tm_mday;
+ pgtm.tm_mon = tm.tm_mon + 1;
+ pgtm.tm_year = tm.tm_year + 1900;
+
+ if (unlikely(tm2timestamp(&pgtm, 0, NULL, &ts) != 0))
+ ereport(ERROR,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("timestamp out of range"));
+
+ PG_RETURN_TIMESTAMP(ts);
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -482,3 +521,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_get0_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_get0_notAfter(cert));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 16646f560e..47ef1d4165 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2379,6 +2379,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>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..2a6725cc1c 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -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>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index a4d2cfdcaf..f754a68107 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -994,7 +994,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 64ff3ce3d6..1f79512b1a 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -35,6 +35,7 @@
#include "storage/latch.h"
#include "utils/guc.h"
#include "utils/memutils.h"
+#include "utils/timestamp.h"
/*
* These SSL-related #includes must come after all system-provided headers.
@@ -79,6 +80,7 @@ static const char *SSLerrmessageExt(unsigned long ecode, const char *replacement
static const char *SSLerrmessage(unsigned long ecode);
static char *X509_NAME_to_cstring(X509_NAME *name);
+static TimestampTz ASN1_TIME_to_timestamptz(const ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool dummy_ssl_passwd_cb_called = false;
@@ -1557,6 +1559,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_get0_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_get0_notAfter(port->peer));
+ else
+ *ptr = 0;
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1700,6 +1720,38 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a PostgreSQL Timestamp datum.
+ */
+static TimestampTz
+ASN1_TIME_to_timestamptz(const ASN1_TIME *ASN1_cert_ts)
+{
+ struct pg_tm pgtm;
+ struct tm tm;
+ int ret;
+ TimestampTz ts;
+
+ ret = ASN1_TIME_to_tm(ASN1_cert_ts, &tm);
+ if (!ret)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("failed to parse certificate validity")));
+
+ pgtm.tm_sec = tm.tm_sec;
+ pgtm.tm_min = tm.tm_min;
+ pgtm.tm_hour = tm.tm_hour;
+ pgtm.tm_mday = tm.tm_mday;
+ pgtm.tm_mon = tm.tm_mon + 1;
+ pgtm.tm_year = tm.tm_year + 1900;
+
+ if (unlikely(tm2timestamp(&pgtm, 0, NULL, &ts) != 0))
+ ereport(ERROR,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("timestamp out of range"));
+
+ return ts;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index 7681b4ba5a..841c980186 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -412,6 +412,8 @@ pgstat_bestart_security(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);
}
#endif
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 9172e1cb9d..77da3db731 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -330,7 +330,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);
@@ -424,7 +424,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
pfree(clipped_activity);
/* leader_pid */
- nulls[29] = true;
+ nulls[31] = true;
proc = BackendPidGetProc(beentry->st_procpid);
@@ -461,8 +461,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)
{
@@ -470,8 +470,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;
}
}
}
@@ -615,35 +615,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
{
@@ -673,6 +683,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index cede992b6e..d979754e59 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5593,9 +5593,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 => '6318', descr => 'describe wait events',
proname => 'pg_get_wait_events', procost => '10', prorows => '250',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 7fe92b1547..a3ed92a2ae 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -323,6 +323,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
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 1c9b4fe14d..e06c001403 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -62,6 +62,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;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 62f69ac20b..ebfa96161a 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1762,7 +1762,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,
@@ -1890,7 +1890,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,
@@ -2098,7 +2098,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,
@@ -2131,8 +2131,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 5422511d4a..20c19de6ec 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -552,8 +552,8 @@ command_like(
'--command' =>
"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.
@@ -754,8 +754,8 @@ command_like(
'--command' =>
"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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E\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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs,2023-06-29 01:01:01+00,2050-01-01 01:01:01+00\E\r?$}mx,
'pg_stat_ssl with client certificate');
# client key with wrong permissions
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index b9eae8d641..7d95f7e8b9 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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';",
--
2.17.1
---- On Mon, 10 Mar 2025 12:29:28 -0700 Cary Huang <cary.huang@highgo.ca> wrote ---
The attached v14 is the rebased patch that updated the OpenSSL API calls to be compatible in
version 1.1.1 (and beyond), which is the new minimum OpenSSL version supported in PostgreSQL.Cary Huang
-------------
HighGo Software Inc. (Canada)
cary.huang@highgo.ca
www.highgo.ca
attached is the rebased (v15) patch
Regards
Cary Huang
Attachments:
v15-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patchapplication/octet-stream; name=v15-0001-Add-notBefore-and-notAfter-to-SSL-cert-info-disp.patchDownload
From 42beac14bf62af042b9601c50c18e423d1840702 Mon Sep 17 00:00:00 2001
From: Cary Huang <cary.huang@highgo.ca>
Date: Thu, 5 Jun 2025 14:57:47 -0700
Subject: [PATCH] v15rebase
---
contrib/sslinfo/Makefile | 2 +-
contrib/sslinfo/meson.build | 1 +
contrib/sslinfo/sslinfo--1.2--1.3.sql | 12 ++++
contrib/sslinfo/sslinfo.c | 71 +++++++++++++++++++++
contrib/sslinfo/sslinfo.control | 2 +-
doc/src/sgml/monitoring.sgml | 20 ++++++
doc/src/sgml/sslinfo.sgml | 30 +++++++++
src/backend/catalog/system_views.sql | 4 +-
src/backend/libpq/be-secure-openssl.c | 52 +++++++++++++++
src/backend/utils/activity/backend_status.c | 2 +
src/backend/utils/adt/pgstatfuncs.c | 46 ++++++++-----
src/include/catalog/pg_proc.dat | 6 +-
src/include/libpq/libpq-be.h | 2 +
src/include/utils/backend_status.h | 3 +
src/test/regress/expected/rules.out | 12 ++--
src/test/ssl/t/001_ssltests.pl | 8 +--
src/test/ssl/t/003_sslinfo.pl | 14 ++++
17 files changed, 255 insertions(+), 32 deletions(-)
create mode 100644 contrib/sslinfo/sslinfo--1.2--1.3.sql
diff --git a/contrib/sslinfo/Makefile b/contrib/sslinfo/Makefile
index 14305594e2..ef1475fffb 100644
--- a/contrib/sslinfo/Makefile
+++ b/contrib/sslinfo/Makefile
@@ -6,7 +6,7 @@ OBJS = \
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
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
index 4c51375920..b560da0820 100644
--- a/contrib/sslinfo/meson.build
+++ b/contrib/sslinfo/meson.build
@@ -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,
)
diff --git a/contrib/sslinfo/sslinfo--1.2--1.3.sql b/contrib/sslinfo/sslinfo--1.2--1.3.sql
new file mode 100644
index 0000000000..424a11afe4
--- /dev/null
+++ b/contrib/sslinfo/sslinfo--1.2--1.3.sql
@@ -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;
diff --git a/contrib/sslinfo/sslinfo.c b/contrib/sslinfo/sslinfo.c
index da70201119..f6d009bb13 100644
--- a/contrib/sslinfo/sslinfo.c
+++ b/contrib/sslinfo/sslinfo.c
@@ -18,6 +18,7 @@
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "utils/builtins.h"
+#include "utils/timestamp.h"
PG_MODULE_MAGIC_EXT(
.name = "sslinfo",
@@ -26,6 +27,7 @@ PG_MODULE_MAGIC_EXT(
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(const ASN1_TIME *time);
/*
* Function context for data persisting over repeated calls.
@@ -217,6 +219,43 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
}
+/*
+ * Converts OpenSSL ASN1_TIME structure into timestamptz
+ *
+ * Parameter: ASN1_TIME timestamp from certificate
+ *
+ * Returns the ASN1_TIME timestamp as a timestamptz datum.
+ */
+static Datum
+ASN1_TIME_to_timestamptz(const ASN1_TIME *ASN1_cert_ts)
+{
+ struct pg_tm pgtm;
+ struct tm tm;
+ int ret;
+ Timestamp ts;
+
+ ret = ASN1_TIME_to_tm(ASN1_cert_ts, &tm);
+ if (!ret)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("failed to parse certificate validity")));
+
+ pgtm.tm_sec = tm.tm_sec;
+ pgtm.tm_min = tm.tm_min;
+ pgtm.tm_hour = tm.tm_hour;
+ pgtm.tm_mday = tm.tm_mday;
+ pgtm.tm_mon = tm.tm_mon + 1;
+ pgtm.tm_year = tm.tm_year + 1900;
+
+ if (unlikely(tm2timestamp(&pgtm, 0, NULL, &ts) != 0))
+ ereport(ERROR,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("timestamp out of range"));
+
+ PG_RETURN_TIMESTAMP(ts);
+}
+
+
/*
* Returns specified field of client certificate distinguished name
*
@@ -474,3 +513,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_get0_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_get0_notAfter(cert));
+}
diff --git a/contrib/sslinfo/sslinfo.control b/contrib/sslinfo/sslinfo.control
index c7754f924c..b53e95b7da 100644
--- a/contrib/sslinfo/sslinfo.control
+++ b/contrib/sslinfo/sslinfo.control
@@ -1,5 +1,5 @@
# sslinfo extension
comment = 'information about SSL certificates'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/sslinfo'
relocatable = true
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 4265a22d4d..30b1ef1b4c 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2398,6 +2398,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>
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index 85d49f6653..2a6725cc1c 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -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>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 08f780a2e6..682498e365 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1002,7 +1002,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;
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 64ff3ce3d6..1f79512b1a 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -35,6 +35,7 @@
#include "storage/latch.h"
#include "utils/guc.h"
#include "utils/memutils.h"
+#include "utils/timestamp.h"
/*
* These SSL-related #includes must come after all system-provided headers.
@@ -79,6 +80,7 @@ static const char *SSLerrmessageExt(unsigned long ecode, const char *replacement
static const char *SSLerrmessage(unsigned long ecode);
static char *X509_NAME_to_cstring(X509_NAME *name);
+static TimestampTz ASN1_TIME_to_timestamptz(const ASN1_TIME *time);
static SSL_CTX *SSL_context = NULL;
static bool dummy_ssl_passwd_cb_called = false;
@@ -1557,6 +1559,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_get0_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_get0_notAfter(port->peer));
+ else
+ *ptr = 0;
+}
+
void
be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
{
@@ -1700,6 +1720,38 @@ X509_NAME_to_cstring(X509_NAME *name)
return result;
}
+/*
+ * Convert an ASN1_TIME to a PostgreSQL Timestamp datum.
+ */
+static TimestampTz
+ASN1_TIME_to_timestamptz(const ASN1_TIME *ASN1_cert_ts)
+{
+ struct pg_tm pgtm;
+ struct tm tm;
+ int ret;
+ TimestampTz ts;
+
+ ret = ASN1_TIME_to_tm(ASN1_cert_ts, &tm);
+ if (!ret)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("failed to parse certificate validity")));
+
+ pgtm.tm_sec = tm.tm_sec;
+ pgtm.tm_min = tm.tm_min;
+ pgtm.tm_hour = tm.tm_hour;
+ pgtm.tm_mday = tm.tm_mday;
+ pgtm.tm_mon = tm.tm_mon + 1;
+ pgtm.tm_year = tm.tm_year + 1900;
+
+ if (unlikely(tm2timestamp(&pgtm, 0, NULL, &ts) != 0))
+ ereport(ERROR,
+ errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("timestamp out of range"));
+
+ return ts;
+}
+
/*
* Convert TLS protocol version GUC enum to OpenSSL values
*
diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c
index a290cc4c97..a098f6ac56 100644
--- a/src/backend/utils/activity/backend_status.c
+++ b/src/backend/utils/activity/backend_status.c
@@ -413,6 +413,8 @@ pgstat_bestart_security(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);
}
#endif
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 1c12ddbae4..baf11eadc0 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -330,7 +330,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);
@@ -424,7 +424,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
pfree(clipped_activity);
/* leader_pid */
- nulls[29] = true;
+ nulls[31] = true;
proc = BackendPidGetProc(beentry->st_procpid);
@@ -461,8 +461,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)
{
@@ -470,8 +470,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;
}
}
}
@@ -615,35 +615,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 == INT64CONST(0))
- nulls[30] = true;
+ nulls[32] = true;
else
- values[30] = Int64GetDatum(beentry->st_query_id);
+ values[32] = Int64GetDatum(beentry->st_query_id);
}
else
{
@@ -673,6 +683,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);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index d3d28a263f..24cb44b53d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5636,9 +5636,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 => '6318', descr => 'describe wait events',
proname => 'pg_get_wait_events', procost => '10', prorows => '250',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index d6e671a638..c2eca60226 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -320,6 +320,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
diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h
index 3016501ac0..4a867087d7 100644
--- a/src/include/utils/backend_status.h
+++ b/src/include/utils/backend_status.h
@@ -62,6 +62,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;
/*
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 6cf828ca8d..80e5351bae 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1783,7 +1783,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,
@@ -1911,7 +1911,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,
@@ -2119,7 +2119,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,
@@ -2152,8 +2152,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,
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 2cb4d0ffd4..484f58e66a 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -580,8 +580,8 @@ command_like(
'--command' =>
"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.
@@ -782,8 +782,8 @@ command_like(
'--command' =>
"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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs\E\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+,/?CN=ssltestuser,$serialno,/?\QCN=Test CA for PostgreSQL SSL regression test client certs,2023-06-29 01:01:01+00,2050-01-01 01:01:01+00\E\r?$}mx,
'pg_stat_ssl with client certificate');
# client key with wrong permissions
diff --git a/src/test/ssl/t/003_sslinfo.pl b/src/test/ssl/t/003_sslinfo.pl
index 3c756489cd..16f2dbda49 100644
--- a/src/test/ssl/t/003_sslinfo.pl
+++ b/src/test/ssl/t/003_sslinfo.pl
@@ -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';",
--
2.17.1