On Thu, Jun 30, 2022 at 2:43 AM Peter Eisentraut
<peter.eisentr...@enterprisedb.com> wrote:
>
> On 13.05.22 00:36, Jacob Champion wrote:
> > v2 limits the maximum subject length and adds the serial number to the
> > logs.
>
> I wrote that pg_stat_ssl uses the *issuer* plus serial number to
> identify a certificate.  What your patch shows is the subject and the
> serial number, which isn't the same thing.  Let's get that sorted out
> one way or the other.

Sorry for the misunderstanding! v3 adds the Issuer to the logs as well.

I wanted to clarify that this "issuer" has not actually been verified,
but all I could come up with was "purported issuer" which doesn't read
well to me. "Claimed issuer"? "Alleged issuer"? Thoughts?

> Another point, your patch produces
>
>      LOG:  connection received: host=localhost port=44120
>      LOG:  client certificate verification failed at depth 1: ...
>      DETAIL:  failed certificate had subject ...
>      LOG:  could not accept SSL connection: certificate verify failed
>
> I guess what we really would like is
>
>      LOG:  connection received: host=localhost port=44120
>      LOG:  could not accept SSL connection: certificate verify failed
>      DETAIL:  client certificate verification failed at depth 1: ...
>      failed certificate had subject ...
>
> But I suppose that would be very cumbersome to produce with the callback
> structure provided by OpenSSL?

I was about to say "yes, very cumbersome", but I actually think we
might be able to do that without bubbling the error up through
multiple callback layers, using SSL_set_ex_data() and friends. I'll
take a closer look.

Thanks!
--Jacob
commit dfe12fa0c3b93cf98169da2095e53edd79c936e6
Author: Jacob Champion <jchamp...@timescale.com>
Date:   Fri Jul 1 13:39:34 2022 -0700

    squash! Log details for client certificate failures
    
    Add the Issuer to the log.

diff --git a/src/backend/libpq/be-secure-openssl.c 
b/src/backend/libpq/be-secure-openssl.c
index 3ccc23ba62..80b361b105 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -1076,6 +1076,40 @@ dummy_ssl_passwd_cb(char *buf, int size, int rwflag, 
void *userdata)
        return 0;
 }
 
+/*
+ * Examines the provided certificate name, and if it's too long to log, 
modifies
+ * and truncates it. The return value is NULL if no truncation was needed; it
+ * otherwise points into the middle of the input string, and should not be
+ * freed.
+ */
+static char *
+truncate_cert_name(char *name)
+{
+       size_t          namelen = strlen(name);
+       char       *truncated;
+
+       /*
+        * Common Names are 64 chars max, so for a common case where the CN is 
the
+        * last field, we can still print the longest possible CN with a 
7-character
+        * prefix (".../CN=[64 chars]"), for a reasonable limit of 71 
characters.
+        */
+#define MAXLEN 71
+
+       if (namelen <= MAXLEN)
+               return NULL;
+
+       /*
+        * Keep the end of the name, not the beginning, since the most specific
+        * field is likely to give users the most information.
+        */
+       truncated = name + namelen - MAXLEN;
+       truncated[0] = truncated[1] = truncated[2] = '.';
+
+#undef MAXLEN
+
+       return truncated;
+}
+
 /*
  *     Certificate verification callback
  *
@@ -1093,8 +1127,8 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
        int                     errcode;
        const char *errstring;
        X509       *cert;
-       char       *certname = NULL;
-       char       *truncated = NULL;
+       char       *subject = NULL, *issuer = NULL;
+       char       *sub_truncated = NULL, *iss_truncated = NULL;
        char       *serialno = NULL;
 
        if (ok)
@@ -1111,33 +1145,18 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
        cert = X509_STORE_CTX_get_current_cert(ctx);
        if (cert)
        {
-               size_t          namelen;
                ASN1_INTEGER *sn;
                BIGNUM     *b;
 
                /*
-                * Get the Subject for logging, but don't let maliciously huge 
certs
-                * flood the logs.
-                *
-                * Common Names are 64 chars max, so for a common case where 
the CN is
-                * the last field, we can still print the longest possible CN 
with a
-                * 7-character prefix (".../CN=[64 chars]"), for a reasonable 
limit of
-                * 71 characters.
+                * Get the Subject and Issuer for logging, but don't let 
maliciously
+                * huge certs flood the logs.
                 */
-#define MAXLEN 71
-               certname = X509_NAME_to_cstring(X509_get_subject_name(cert));
-               namelen = strlen(certname);
+               subject = X509_NAME_to_cstring(X509_get_subject_name(cert));
+               sub_truncated = truncate_cert_name(subject);
 
-               if (namelen > MAXLEN)
-               {
-                       /*
-                        * Keep the end of the Subject, not the beginning, 
since the most
-                        * specific field is likely to give users the most 
information.
-                        */
-                       truncated = certname + namelen - MAXLEN;
-                       truncated[0] = truncated[1] = truncated[2] = '.';
-               }
-#undef MAXLEN
+               issuer = X509_NAME_to_cstring(X509_get_issuer_name(cert));
+               iss_truncated = truncate_cert_name(issuer);
 
                /*
                 * Pull the serial number, too, in case a Subject is still 
ambiguous.
@@ -1154,14 +1173,19 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
                        (errmsg("client certificate verification failed at 
depth %d: %s",
                                        depth, errstring),
                         /* only print detail if we have a certificate to print 
*/
-                        certname && errdetail("failed certificate had subject 
'%s', serial number %s",
-                                                                  truncated ? 
truncated : certname,
-                                                                  serialno ? 
serialno : _("unknown"))));
+                        subject && errdetail("failed certificate had subject 
'%s', "
+                                                                       "serial 
number %s, "
+                                                                       
"purported issuer '%s'",
+                                                                 sub_truncated 
? sub_truncated : subject,
+                                                                 serialno ? 
serialno : _("unknown"),
+                                                                 iss_truncated 
? iss_truncated : issuer)));
 
        if (serialno)
                OPENSSL_free(serialno);
-       if (certname)
-               pfree(certname);
+       if (issuer)
+               pfree(issuer);
+       if (subject)
+               pfree(subject);
 
        return ok;
 }
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 7378cb5dc6..a9b737ed09 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -685,7 +685,7 @@ $node->connect_fails(
        expected_stderr => qr/SSL error: sslv3 alert certificate revoked/,
        log_like => [
                qr/client certificate verification failed at depth 0: 
certificate revoked/,
-               qr/failed certificate had subject '\/CN=ssltestuser', serial 
number 2315134995201656577/,
+               qr/failed certificate had subject '\/CN=ssltestuser', serial 
number 2315134995201656577, purported issuer '\/CN=Test CA for PostgreSQL SSL 
regression test client certs'/,
        ],
        # revoked certificates should not authenticate the user
        log_unlike => [qr/connection authenticated:/],);
@@ -737,7 +737,7 @@ $node->connect_fails(
        expected_stderr => qr/SSL error: tlsv1 alert unknown ca/,
        log_like => [
                qr/client certificate verification failed at depth 0: unable to 
get local issuer certificate/,
-               qr/failed certificate had subject '\/CN=ssltestuser', serial 
number 2315134995201656576/,
+               qr/failed certificate had subject '\/CN=ssltestuser', serial 
number 2315134995201656576, purported issuer '\/CN=Test CA for PostgreSQL SSL 
regression test client certs'/,
        ]);
 
 $node->connect_fails(
@@ -746,7 +746,7 @@ $node->connect_fails(
        expected_stderr => qr/SSL error: tlsv1 alert unknown ca/,
        log_like => [
                qr/client certificate verification failed at depth 0: unable to 
get local issuer certificate/,
-               qr/failed certificate had subject 
'\.\.\.\/CN=ssl-123456789012345678901234567890123456789012345678901234567890', 
serial number 2315418733629425152/,
+               qr/failed certificate had subject 
'\.\.\.\/CN=ssl-123456789012345678901234567890123456789012345678901234567890', 
serial number 2315418733629425152, purported issuer '\/CN=Test CA for 
PostgreSQL SSL regression test client certs'/,
        ]);
 
 # Use an invalid cafile here so that the next test won't be able to verify the
@@ -761,7 +761,7 @@ $node->connect_fails(
        expected_stderr => qr/SSL error: tlsv1 alert unknown ca/,
        log_like => [
                qr/client certificate verification failed at depth 1: unable to 
get local issuer certificate/,
-               qr/failed certificate had subject '\/CN=Test CA for PostgreSQL 
SSL regression test client certs', serial number 2315134995201656577/,
+               qr/failed certificate had subject '\/CN=Test CA for PostgreSQL 
SSL regression test client certs', serial number 2315134995201656577, purported 
issuer '\/CN=Test root CA for PostgreSQL SSL regression test suite'/,
        ]);
 
 # test server-side CRL directory
@@ -778,7 +778,7 @@ $node->connect_fails(
        expected_stderr => qr/SSL error: sslv3 alert certificate revoked/,
        log_like => [
                qr/client certificate verification failed at depth 0: 
certificate revoked/,
-               qr/failed certificate had subject '\/CN=ssltestuser', serial 
number 2315134995201656577/,
+               qr/failed certificate had subject '\/CN=ssltestuser', serial 
number 2315134995201656577, purported issuer '\/CN=Test CA for PostgreSQL SSL 
regression test client certs'/,
        ]);
 
 done_testing();
From 92d601172133347dd319a6ff8d1323aaafb3cf52 Mon Sep 17 00:00:00 2001
From: Jacob Champion <pchamp...@vmware.com>
Date: Mon, 29 Mar 2021 10:07:31 -0700
Subject: [PATCH v3] Log details for client certificate failures

Currently, debugging client cert verification failures is mostly limited
to looking at the TLS alert code on the client side. For simple
deployments, sometimes it's enough to see "sslv3 alert certificate
revoked" and know exactly what needs to be fixed, but if you add any
more complexity (multiple CA layers, misconfigured CA certificates,
etc.), trying to debug what happened based on the TLS alert alone can be
an exercise in frustration.

Luckily, the server has more information about exactly what failed in
the chain, and we already have the requisite callback implemented as a
stub. Fill it out with error handling and add a COMMERROR log so that a
DBA can debug client failures more easily. It ends up looking like

    LOG:  connection received: host=localhost port=44120
    LOG:  client certificate verification failed at depth 1: unable to get local issuer certificate
    DETAIL:  failed certificate had subject '/CN=Test CA for PostgreSQL SSL regression test client certs', serial number 2315134995201656577, purported issuer '/CN=Root CA'
    LOG:  could not accept SSL connection: certificate verify failed

The length of the Subject and Issuer strings is limited to prevent
malicious client certs from spamming the logs. In case the truncation
makes things ambiguous, the certificate's serial number is also logged.
---
 src/backend/libpq/be-secure-openssl.c | 101 +++++++++++++++++++++++++-
 src/test/ssl/conf/client-long.config  |  14 ++++
 src/test/ssl/ssl/client-long.crt      | Bin 0 -> 1224 bytes
 src/test/ssl/ssl/client-long.key      |  27 +++++++
 src/test/ssl/sslfiles.mk              |   2 +-
 src/test/ssl/t/001_ssltests.pl        |  40 +++++++++-
 src/test/ssl/t/SSL/Backend/OpenSSL.pm |   2 +-
 7 files changed, 180 insertions(+), 6 deletions(-)
 create mode 100644 src/test/ssl/conf/client-long.config
 create mode 100644 src/test/ssl/ssl/client-long.crt
 create mode 100644 src/test/ssl/ssl/client-long.key

diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 3d0168a369..80b361b105 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -1076,12 +1076,45 @@ dummy_ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata)
 	return 0;
 }
 
+/*
+ * Examines the provided certificate name, and if it's too long to log, modifies
+ * and truncates it. The return value is NULL if no truncation was needed; it
+ * otherwise points into the middle of the input string, and should not be
+ * freed.
+ */
+static char *
+truncate_cert_name(char *name)
+{
+	size_t		namelen = strlen(name);
+	char	   *truncated;
+
+	/*
+	 * Common Names are 64 chars max, so for a common case where the CN is the
+	 * last field, we can still print the longest possible CN with a 7-character
+	 * prefix (".../CN=[64 chars]"), for a reasonable limit of 71 characters.
+	 */
+#define MAXLEN 71
+
+	if (namelen <= MAXLEN)
+		return NULL;
+
+	/*
+	 * Keep the end of the name, not the beginning, since the most specific
+	 * field is likely to give users the most information.
+	 */
+	truncated = name + namelen - MAXLEN;
+	truncated[0] = truncated[1] = truncated[2] = '.';
+
+#undef MAXLEN
+
+	return truncated;
+}
+
 /*
  *	Certificate verification callback
  *
  *	This callback allows us to log intermediate problems during
- *	verification, but for now we'll see if the final error message
- *	contains enough information.
+ *	verification.
  *
  *	This callback also allows us to override the default acceptance
  *	criteria (e.g., accepting self-signed or expired certs), but
@@ -1090,6 +1123,70 @@ dummy_ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata)
 static int
 verify_cb(int ok, X509_STORE_CTX *ctx)
 {
+	int			depth;
+	int			errcode;
+	const char *errstring;
+	X509	   *cert;
+	char	   *subject = NULL, *issuer = NULL;
+	char	   *sub_truncated = NULL, *iss_truncated = NULL;
+	char	   *serialno = NULL;
+
+	if (ok)
+	{
+		/* Nothing to do for the successful case. */
+		return ok;
+	}
+
+	/* Pull all the information we have on the verification failure. */
+	depth = X509_STORE_CTX_get_error_depth(ctx);
+	errcode = X509_STORE_CTX_get_error(ctx);
+	errstring = X509_verify_cert_error_string(errcode);
+
+	cert = X509_STORE_CTX_get_current_cert(ctx);
+	if (cert)
+	{
+		ASN1_INTEGER *sn;
+		BIGNUM	   *b;
+
+		/*
+		 * Get the Subject and Issuer for logging, but don't let maliciously
+		 * huge certs flood the logs.
+		 */
+		subject = X509_NAME_to_cstring(X509_get_subject_name(cert));
+		sub_truncated = truncate_cert_name(subject);
+
+		issuer = X509_NAME_to_cstring(X509_get_issuer_name(cert));
+		iss_truncated = truncate_cert_name(issuer);
+
+		/*
+		 * Pull the serial number, too, in case a Subject is still ambiguous.
+		 * This mirrors be_tls_get_peer_serial().
+		 */
+		sn = X509_get_serialNumber(cert);
+		b = ASN1_INTEGER_to_BN(sn, NULL);
+		serialno = BN_bn2dec(b);
+
+		BN_free(b);
+	}
+
+	ereport(COMMERROR,
+			(errmsg("client certificate verification failed at depth %d: %s",
+					depth, errstring),
+			 /* only print detail if we have a certificate to print */
+			 subject && errdetail("failed certificate had subject '%s', "
+									"serial number %s, "
+									"purported issuer '%s'",
+								  sub_truncated ? sub_truncated : subject,
+								  serialno ? serialno : _("unknown"),
+								  iss_truncated ? iss_truncated : issuer)));
+
+	if (serialno)
+		OPENSSL_free(serialno);
+	if (issuer)
+		pfree(issuer);
+	if (subject)
+		pfree(subject);
+
 	return ok;
 }
 
diff --git a/src/test/ssl/conf/client-long.config b/src/test/ssl/conf/client-long.config
new file mode 100644
index 0000000000..0e92a8fbfe
--- /dev/null
+++ b/src/test/ssl/conf/client-long.config
@@ -0,0 +1,14 @@
+# An OpenSSL format CSR config file for creating a client certificate with a
+# long Subject.
+
+[ req ]
+distinguished_name     = req_distinguished_name
+prompt                 = no
+
+[ req_distinguished_name ]
+# Common Names are 64 characters max
+CN                     = ssl-123456789012345678901234567890123456789012345678901234567890
+OU                     = Some Organizational Unit
+O                      = PostgreSQL Global Development Group
+
+# no extensions in client certs
diff --git a/src/test/ssl/ssl/client-long.crt b/src/test/ssl/ssl/client-long.crt
new file mode 100644
index 0000000000000000000000000000000000000000..a1db55b5c3e7c6923f978810c38d5f5d50656608
GIT binary patch
literal 1224
zcmZ`($+D|B4Bhh;y-(c=L*T*UEo{t~FqkmJ>=FhuB_tsU!`C<WzN+p;S8Jh?k55@T
zl1pD-t3l1M+`m*U2rb=GL8yI$UyNf}C}~s`w3fR18U|JrXaqQbHPqw7I9eA0VGXKd
z1RTwpFajG$-53JLak-#lG67S}YBaqnv!%mNCIq+a8i!Fd(ui{%%e1>xu)9of?-zbY
zb0c1I6*d>6>n=A;8N$bNZaSk`Wv<g$qZ?|o(`c-Vu#l{ni`vl(E#V)mQQ-|~gQNBa
z;3ADt>DWYuvgAfSr?DG^Dl{*KQj=t)ff4g*GJP_G`^gpv_9s7q$qGUFN5<eVhVFhY
zNkl`zzL7+{7gwD<C(8T#fp|UVNVgp=`^g5z39M3v!*`Vn=G-RRF<uBJr*T*}B!ah=
z>x9<gqKJ1FDmv(2;{WlOKg6~FM{7iw*!w=Us!!&Ewet`IM5*QjwBF-hU1JDbI$aC1
zj)ON0$If6d*E_t!Wi3{%ZNIBX<|&Zm6C!2}el;_f#KmoHWcZ3|5j0ASs(V?#ixHil
z1{TjuNGam(PScL8(?8)JK9vpk<|f13%2?=H8f`p$diu2Mch)n`9_K#QF?)ME=lD_=
zCx*?@9F{|Pjxiyx2Y4-&wT;&Q<5exc>7Y{jlH80+b}(5?KEdXJS<5##!4jA2k@$?$
zurV2(n-c2EmLH&Z3}PC_AbS$(;X^A7+tMf`>2-~vm5}Tqi8Fm5ZZj6|jenk)#=nh2
zQMUQ5l<b@Y2B&js|BH(Jz4tXz7r-pBXG_Xpum>`+9rTbYDUZ+5-X*z;8Ftx^yez9=
z)Bp&93u*hP+S*V?76Lrz0C?*JH1K?iPcE8hwD@y-eT!*+kY+gqOnNzDZia-tRYNca
zEy^XS_V-F8h0>ni+z)b`Np;_Ul*D_PSn4ZZpvUtk-?5n)Ty^IB9<3qWB`tex%Gcd{
z`}&=$=3dUXm^?4qRd~3C_~>rpQK{tm-jk31D#fMS^Lx|Q7e*<n)JeI;09xRxu_H$j
z-p|oHg`zP()9x~KrQ~lFIAr3EM9Jjy_f^d{uq9NSN{d;5UY<f3=y9iZAOOlvq4yJe
zh@YqDj9iITBU_fSeI+Uuz{{cwA;lxhi5cc{apW1r7sm?ak?4K`&)*yxEi8h<)_1U+
qGoCuXmMKL%M8{Grrq9iN)boztb^&+U4a@lZH}kWXG#CAMSN#oVvxiUs

literal 0
HcmV?d00001

diff --git a/src/test/ssl/ssl/client-long.key b/src/test/ssl/ssl/client-long.key
new file mode 100644
index 0000000000..5b455a021f
--- /dev/null
+++ b/src/test/ssl/ssl/client-long.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA2DGZ4eJVG4FPCUZDWgzYzVyRAIj+jiFhw70Fh3ENgeIDuPLV
+ZV6fKPwG1SLkCP1UOGl+K57ANqsZDlpOCAPWkyOTDQyisEoGv37W7XEYf/xDeWSB
+T45Bes+CWjgitVypqhkVDSe4xpVuJ5fR0PJN+xNpVBhi2oC3OEj9QZIg6GTb6UH1
+8/ryPD1wsfRBi9H6pDQg8bXcjnOZJg8yPRVjAyf1MX3/awE5JFWBNUBytiA5AuTe
+z98Z7rq2ZUEhZhyrrnKCoPX7B6749rGM+fCx5+R2d/ol1hEbUXUKjuDnamg8RiJ4
+Ad9A4nr2wbQtjHSUE4MLr2q9InhZ0JDTMrDbzwIDAQABAoIBADwJykpIqIny5xgU
+QzAG0U52nm4fnVGrQ5MwMxDh/HZNZes+xLRaCqk/FEasYdd9Qp5H7Zn/hDGqYlLy
+ESl4p2ZFQtkk4SlD5YvYladq+PrR+4sCtkZ5owWQCwsy+7CSAywRux7kIRRE+0pT
+hxkXsUBAq8eG3i0AAeHHo01KX4kptlJ5d1pFKKAPThTUHCT4VPHg8r59IdsNy6wC
++0E5ZRWsVUePy+ERuarX/um896hgbaiDJLFk02Orlc87+OBmRwO8J+KoUOEcAiTO
+OZqGGaDEn5Y2mEdp2cCmq7+Izcklaha6CPsoV8+O2HK8PKvBIQmlgbDmal4/RNqr
+JFqYz0ECgYEA+5z74Tmj+tzH57lcdMqVpndG39N8spBe8JbiFL16qOb6gRDytXjc
+hY6IQo4JStpJulnPBZ5JQSbSBgCOzYWJJVBnnwMJKjNCd1th4znjxxMOe4LiDTtw
+D3hQtzBU9FlI2sjWEUKf1xCyi9N41ApQC5eDWWd/0GN9+xAsxRjLL00CgYEA2/aH
+4kNVsBHQ7vmv+sNsWeIgKg7PC7hRjcCYQG9ylBbBnFtv5XJYicXwqorqngzJPoGw
+gB7iaSWL1UNAOSWRSFYe+woPpkY7n6Pbq211nzqV1avAdVrLylJwyE+EOQgTS30D
+8BHv0I714PMd/QLK5NSUEr1IRtCfLeMpcSg6YYsCgYEAv3O86KxeTMTvyy9s3WVE
+p4y8vhUDHi/iPbjhQBzJF3nhhJGrzE+xpGJG5jWDdpRQY15wuvqtDMkIKA8GmfWQ
+3Hao0gKSV6z3VzCOdEKZQeILNAnsDVt7shm/eRRqoB7L48XLtQh37UJESUbY+qb6
+L0fTZxTs2VjLBF1TY4mxGUUCgYEA1PLENKnJkA5/fowd8aA2CoKfbvgtPARyd9Bn
+1aHPhEzPnabsGm7sBl2qFAEvCFoKjkgR7sd3nCHsUUetKmYTU7uEfLcN1YSS/oct
+CLaMs92M53JCfZqsRrAvXc2VjX0i6Ocb49QJnph4tBHKC4MjmAuxWr8C9QPNxyfv
+nAw9EOcCgYBYzejUzp6xiv5YzpwIncIF0A5E6VITcsW+LOR/FZOUPso0X2hQoIEs
+wx8HjKCGfvX6628vnaWJC099hTmOzVwpEgik5zOmeAmZ//gt2I53Yg/loQUzH0CD
+iXxrg/4Up7Yxx897w11ukOZv2xwmAFO1o52Q8k7d5FiMfEIzAkS3Pg==
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/ssl/sslfiles.mk b/src/test/ssl/sslfiles.mk
index cc023667af..5f67aba795 100644
--- a/src/test/ssl/sslfiles.mk
+++ b/src/test/ssl/sslfiles.mk
@@ -33,7 +33,7 @@ SERVERS := server-cn-and-alt-names \
 	server-multiple-alt-names \
 	server-no-names \
 	server-revoked
-CLIENTS := client client-dn client-revoked client_ext
+CLIENTS := client client-dn client-revoked client_ext client-long
 
 #
 # To add a new non-standard key, add it to SPECIAL_KEYS and then add a recipe
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 707f4005af..a9b737ed09 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -683,6 +683,10 @@ $node->connect_fails(
 	  . sslkey('client-revoked.key'),
 	"certificate authorization fails with revoked client cert",
 	expected_stderr => qr/SSL error: sslv3 alert certificate revoked/,
+	log_like => [
+		qr/client certificate verification failed at depth 0: certificate revoked/,
+		qr/failed certificate had subject '\/CN=ssltestuser', serial number 2315134995201656577, purported issuer '\/CN=Test CA for PostgreSQL SSL regression test client certs'/,
+	],
 	# revoked certificates should not authenticate the user
 	log_unlike => [qr/connection authenticated:/],);
 
@@ -730,7 +734,35 @@ $node->connect_ok(
 $node->connect_fails(
 	$common_connstr . " " . "sslmode=require sslcert=ssl/client.crt",
 	"intermediate client certificate is missing",
-	expected_stderr => qr/SSL error: tlsv1 alert unknown ca/);
+	expected_stderr => qr/SSL error: tlsv1 alert unknown ca/,
+	log_like => [
+		qr/client certificate verification failed at depth 0: unable to get local issuer certificate/,
+		qr/failed certificate had subject '\/CN=ssltestuser', serial number 2315134995201656576, purported issuer '\/CN=Test CA for PostgreSQL SSL regression test client certs'/,
+	]);
+
+$node->connect_fails(
+	"$common_connstr sslmode=require sslcert=ssl/client-long.crt " . sslkey('client-long.key'),
+	"logged client certificate Subjects are truncated if they're too long",
+	expected_stderr => qr/SSL error: tlsv1 alert unknown ca/,
+	log_like => [
+		qr/client certificate verification failed at depth 0: unable to get local issuer certificate/,
+		qr/failed certificate had subject '\.\.\.\/CN=ssl-123456789012345678901234567890123456789012345678901234567890', serial number 2315418733629425152, purported issuer '\/CN=Test CA for PostgreSQL SSL regression test client certs'/,
+	]);
+
+# Use an invalid cafile here so that the next test won't be able to verify the
+# client CA.
+switch_server_cert($node, certfile => 'server-cn-only', cafile => 'server-cn-only');
+
+# intermediate CA is provided but doesn't have a trusted root (checks error
+# logging for cert chain depths > 0)
+$node->connect_fails(
+	"$common_connstr sslmode=require sslcert=ssl/client+client_ca.crt",
+	"intermediate client certificate is untrusted",
+	expected_stderr => qr/SSL error: tlsv1 alert unknown ca/,
+	log_like => [
+		qr/client certificate verification failed at depth 1: unable to get local issuer certificate/,
+		qr/failed certificate had subject '\/CN=Test CA for PostgreSQL SSL regression test client certs', serial number 2315134995201656577, purported issuer '\/CN=Test root CA for PostgreSQL SSL regression test suite'/,
+	]);
 
 # test server-side CRL directory
 switch_server_cert(
@@ -743,6 +775,10 @@ $node->connect_fails(
 	"$common_connstr user=ssltestuser sslcert=ssl/client-revoked.crt "
 	  . sslkey('client-revoked.key'),
 	"certificate authorization fails with revoked client cert with server-side CRL directory",
-	expected_stderr => qr/SSL error: sslv3 alert certificate revoked/);
+	expected_stderr => qr/SSL error: sslv3 alert certificate revoked/,
+	log_like => [
+		qr/client certificate verification failed at depth 0: certificate revoked/,
+		qr/failed certificate had subject '\/CN=ssltestuser', serial number 2315134995201656577, purported issuer '\/CN=Test CA for PostgreSQL SSL regression test client certs'/,
+	]);
 
 done_testing();
diff --git a/src/test/ssl/t/SSL/Backend/OpenSSL.pm b/src/test/ssl/t/SSL/Backend/OpenSSL.pm
index aed6005b43..a43e64c04f 100644
--- a/src/test/ssl/t/SSL/Backend/OpenSSL.pm
+++ b/src/test/ssl/t/SSL/Backend/OpenSSL.pm
@@ -88,7 +88,7 @@ sub init
 		"client.key",               "client-revoked.key",
 		"client-der.key",           "client-encrypted-pem.key",
 		"client-encrypted-der.key", "client-dn.key",
-		"client_ext.key");
+		"client_ext.key",           "client-long.key");
 	foreach my $keyfile (@keys)
 	{
 		copy("ssl/$keyfile", "$cert_tempdir/$keyfile")
-- 
2.25.1

Reply via email to