Is it worth accepting multiple CRLs?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Is it worth accepting multiple CRLs?

Kyotaro Horiguchi-4
Hello.

PostgreSQL server accepts only one CRL file. It is easy to expand
be_tls_init to accept a directory set in ssl_crl_file. But I'm not
sure CRL is actually even utilized in the field so that could ends
with just bloating the documentation.

Is it work doing?

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center


Reply | Threaded
Open this post in threaded view
|

Re: Is it worth accepting multiple CRLs?

Henry B Hotz
A CA may issue a CRL infrequently, but issue a delta-CRL frequently. Does the logic support this properly?

Personal email. [hidden email]

> On Jul 31, 2020, at 1:39 AM, Kyotaro Horiguchi <[hidden email]> wrote:
>
> ´╗┐Hello.
>
> PostgreSQL server accepts only one CRL file. It is easy to expand
> be_tls_init to accept a directory set in ssl_crl_file. But I'm not
> sure CRL is actually even utilized in the field so that could ends
> with just bloating the documentation.
>
> Is it work doing?
>
> regards.
>
> --
> Kyotaro Horiguchi
> NTT Open Source Software Center
>
>



Reply | Threaded
Open this post in threaded view
|

Re: Is it worth accepting multiple CRLs?

Stephen Frost
In reply to this post by Kyotaro Horiguchi-4
Greetings,

* Kyotaro Horiguchi ([hidden email]) wrote:
> PostgreSQL server accepts only one CRL file. It is easy to expand
> be_tls_init to accept a directory set in ssl_crl_file. But I'm not
> sure CRL is actually even utilized in the field so that could ends
> with just bloating the documentation.
>
> Is it work doing?

Yes, CRLs are absolutely used in the field and having this would be
nice.

Thanks,

Stephen

signature.asc (836 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Is it worth accepting multiple CRLs?

Kyotaro Horiguchi-4
In reply to this post by Henry B Hotz
At Fri, 31 Jul 2020 05:53:53 -0700, Henry B Hotz <[hidden email]> wrote in
> A CA may issue a CRL infrequently, but issue a delta-CRL frequently. Does the logic support this properly?

If you are talking about regsitering new revokations while server is
running, it checks newer CRLs upon each lookup according to the
documentation [1], so a new Delta-CRL can be added after server
start. If server restart is allowed, the CRL file specified by
ssl_crl_file can contain multiple CRLs by just concatenation.

[1]: https://www.openssl.org/docs/man1.1.1/man3/X509_LOOKUP_hash_dir.html

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center


Reply | Threaded
Open this post in threaded view
|

Re: Is it worth accepting multiple CRLs?

Kyotaro Horiguchi-4
In reply to this post by Stephen Frost
At Fri, 31 Jul 2020 09:00:14 -0400, Stephen Frost <[hidden email]> wrote in

> Greetings,
>
> * Kyotaro Horiguchi ([hidden email]) wrote:
> > PostgreSQL server accepts only one CRL file. It is easy to expand
> > be_tls_init to accept a directory set in ssl_crl_file. But I'm not
> > sure CRL is actually even utilized in the field so that could ends
> > with just bloating the documentation.
> >
> > Is it work doing?
>
> Yes, CRLs are absolutely used in the field and having this would be
> nice.

Thanks for the opinion. I'll continue working on this.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center


Reply | Threaded
Open this post in threaded view
|

Re: Is it worth accepting multiple CRLs?

Kyotaro Horiguchi-4
In reply to this post by Kyotaro Horiguchi-4
Uggg.

At Mon, 03 Aug 2020 16:19:37 +0900 (JST), Kyotaro Horiguchi <[hidden email]> wrote in
> At Fri, 31 Jul 2020 05:53:53 -0700, Henry B Hotz <[hidden email]> wrote in
> > A CA may issue a CRL infrequently, but issue a delta-CRL frequently. Does the logic support this properly?
>
> If you are talking about regsitering new revokations while server is
> running, it checks newer CRLs upon each lookup according to the
> documentation [1], so a new Delta-CRL can be added after server
> start. If server restart is allowed, the CRL file specified by

I didin't know that ssl files are reloaded by SIGHUP (pg_ctl
reload). So the ssl_crl_file is also reloaded on server reload.

> ssl_crl_file can contain multiple CRLs by just concatenation.
>
> [1]: https://www.openssl.org/docs/man1.1.1/man3/X509_LOOKUP_hash_dir.html

Still on-demand loading is the advantage of the hashed directory
method.  I'll continue working..

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center


Reply | Threaded
Open this post in threaded view
|

Re: Is it worth accepting multiple CRLs?

Kyotaro Horiguchi-4
In reply to this post by Kyotaro Horiguchi-4
At Mon, 03 Aug 2020 16:20:40 +0900 (JST), Kyotaro Horiguchi <[hidden email]> wrote in
> Thanks for the opinion. I'll continue working on this.

This is it, but..

Looking closer I realized that certificates are verified in each
backend so CRL cache doesn't work at all for the hashed directory
method. Therefore, all CRL files relevant to a certificate to be
verfied are loaded every time a backend starts.

The only advantage of this is avoiding irrelevant CRLs from being
loaded in exchange of loading relevant CRLs at every session
start. Session startup gets slower by many delta CRLs from the same
CA.

Seems far from promising.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center



From 80a20df187bb2a8555996d7aecb951d345cf51c2 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <[hidden email]>
Date: Tue, 21 Jul 2020 23:01:27 +0900
Subject: [PATCH v1] Allow directory name for GUC ssl_crl_file and connection
 option sslcrl

X509_STORE_load_locations accepts a directory, which leads to
on-demand loading method with which method only relevant CRLs are
loaded.
---
 doc/src/sgml/config.sgml                  | 10 ++++----
 doc/src/sgml/libpq.sgml                   | 10 +++++---
 doc/src/sgml/runtime.sgml                 | 30 ++++++++++++++++++++++
 src/backend/libpq/be-secure-openssl.c     | 12 ++++++++-
 src/interfaces/libpq/fe-secure-openssl.c  | 12 ++++++++-
 src/test/ssl/Makefile                     | 13 +++++++++-
 src/test/ssl/ssl/clientcrldir/9bb9e3c3.r0 | 11 ++++++++
 src/test/ssl/ssl/clientcrldir/a3d11bff.r0 | 11 ++++++++
 src/test/ssl/ssl/servercrldir/a3d11bff.r0 | 11 ++++++++
 src/test/ssl/ssl/servercrldir/a836cc2d.r0 | 11 ++++++++
 src/test/ssl/t/001_ssltests.pl            | 31 +++++++++++++++++++++--
 src/test/ssl/t/SSLServer.pm               |  5 +++-
 12 files changed, 152 insertions(+), 15 deletions(-)
 create mode 100644 src/test/ssl/ssl/clientcrldir/9bb9e3c3.r0
 create mode 100644 src/test/ssl/ssl/clientcrldir/a3d11bff.r0
 create mode 100644 src/test/ssl/ssl/servercrldir/a3d11bff.r0
 create mode 100644 src/test/ssl/ssl/servercrldir/a836cc2d.r0

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 7a7177c550..a3e81619c9 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1182,11 +1182,11 @@ include_dir 'conf.d'
       <listitem>
        <para>
         Specifies the name of the file containing the SSL server certificate
-        revocation list (CRL).
-        Relative paths are relative to the data directory.
-        This parameter can only be set in the <filename>postgresql.conf</filename>
-        file or on the server command line.
-        The default is empty, meaning no CRL file is loaded.
+        revocation list (CRL) or the directory containing CRL files.  Relative
+        paths are relative to the data directory.  This parameter can only be
+        set in the <filename>postgresql.conf</filename> file or on the server
+        command line.  The default is empty, meaning no CRL file is
+        loaded. See <xref linkend="ssl-crl-files"/> for details.
        </para>
       </listitem>
      </varlistentry>
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index f7b765f76d..96bfbcfd82 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1705,10 +1705,12 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
       <listitem>
        <para>
         This parameter specifies the file name of the SSL certificate
-        revocation list (CRL).  Certificates listed in this file, if it
-        exists, will be rejected while attempting to authenticate the
-        server's certificate.  The default is
-        <filename>~/.postgresql/root.crl</filename>.
+        revocation list (CRL) or the directory name that contains CRL files.
+        Certificates listed in this file or directoty, if it exists, will be
+        rejected while attempting to authenticate the server's certificate.
+        The default is
+        <filename>~/.postgresql/root.crl</filename>. See
+        <xref linkend="ssl-crl-files"/> for details.
        </para>
       </listitem>
      </varlistentry>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index c8698898f3..5d7fd48ad7 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -2486,6 +2486,36 @@ openssl x509 -req -in server.csr -text -days 365 \
    </para>
   </sect2>
 
+  <sect2 id="ssl-crl-files">
+    <title>Certification Revokation List files</title>
+
+    <para> The server setting <xref linkend="guc-ssl-crl-file"/> and the
+    connection option <xref linkend="libpq-connect-sslcrl"/> specify either a
+    file containing one or more CRL, or a directory containing a separate file
+    for every CRL. In the first method, file method, the all CRLs in the file
+    is loaded at server start time or by reloading config file
+    (<command>pg_ctl reload</command>). In the second method, hashed directory
+    method, CRL files are loaded on-demand, that is, only the relevant CRL
+    files are loaded at connection time.
+    </para>
+    <para>
+    The CRL file used for the file method can contain multiple CRLs, like
+    certificates, by just concatenated if it is in PEM format.  In the hashed
+    directory method, every file in the directory has the name
+    with <parameter>hash</parameter>.r<parameter>N</parameter> format,
+    where <parameter>hash</parameter> is the hash value of the issuer of the
+    CRL and <parameter>N</parameter> is a sequence number that starts at
+    zero. The hash value is calculated using openssl command. In both cases
+    the CRLs from all CAs involved in a certificate chain are needed to verify
+    a certificate, even if some or all of them are empty.
+<programlisting>
+$ openssl crl -hash -noout -in foo.crl
+98668507
+$ cp foo.crl $PGDATA/crldir/98668507.r0
+</programlisting>
+    </para>
+  </sect2>
+
  </sect1>
 
  <sect1 id="gssapi-enc">
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 8b21ff4065..d85dc710a4 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -289,8 +289,18 @@ be_tls_init(bool isServerStart)
 
  if (cvstore)
  {
+ char *filename = NULL;
+ char *dirname = NULL;
+ struct stat statbuf;
+
+ /* identify whether it is a file or a directoty */
+ if (stat(ssl_crl_file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
+ dirname = ssl_crl_file;
+ else
+ filename = ssl_crl_file;
+
  /* Set the flags to check against the complete CRL chain */
- if (X509_STORE_load_locations(cvstore, ssl_crl_file, NULL) == 1)
+ if (X509_STORE_load_locations(cvstore, filename, dirname) == 1)
  {
  X509_STORE_set_flags(cvstore,
  X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index d609a38bbe..1ae60226b1 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -936,6 +936,10 @@ initialize_SSL(PGconn *conn)
 
  if ((cvstore = SSL_CTX_get_cert_store(SSL_context)) != NULL)
  {
+ char *filename = NULL;
+ char *dirname = NULL;
+ struct stat statbuf;
+
  if (conn->sslcrl && strlen(conn->sslcrl) > 0)
  strlcpy(fnbuf, conn->sslcrl, sizeof(fnbuf));
  else if (have_homedir)
@@ -943,9 +947,15 @@ initialize_SSL(PGconn *conn)
  else
  fnbuf[0] = '\0';
 
+ /* Identify whether it is a file or a directory */
+ if (stat(fnbuf, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
+ dirname = fnbuf;
+ else
+ filename = fnbuf;
+
  /* Set the flags to check against the complete CRL chain */
  if (fnbuf[0] != '\0' &&
- X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1)
+ X509_STORE_load_locations(cvstore, filename, dirname) == 1)
  {
  X509_STORE_set_flags(cvstore,
  X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
diff --git a/src/test/ssl/Makefile b/src/test/ssl/Makefile
index 777ee39413..b04e532295 100644
--- a/src/test/ssl/Makefile
+++ b/src/test/ssl/Makefile
@@ -30,12 +30,14 @@ SSLFILES := $(CERTIFICATES:%=ssl/%.key) $(CERTIFICATES:%=ssl/%.crt) \
  ssl/client+client_ca.crt ssl/client-der.key \
  ssl/client-encrypted-pem.key ssl/client-encrypted-der.key
 
+SSLDIRS := ssl/clientcrldir ssl/servercrldir
+
 # This target re-generates all the key and certificate files. Usually we just
 # use the ones that are committed to the tree without rebuilding them.
 #
 # This target will fail unless preceded by sslfiles-clean.
 #
-sslfiles: $(SSLFILES)
+sslfiles: $(SSLFILES) $(SSLDIRS)
 
 # OpenSSL requires a directory to put all generated certificates in. We don't
 # use this for anything, but we need a location.
@@ -146,10 +148,19 @@ ssl/root+server.crl: ssl/root.crl ssl/server.crl
  cat $^ > $@
 ssl/root+client.crl: ssl/root.crl ssl/client.crl
  cat $^ > $@
+ssl/servercrldir: ssl/server.crl
+ mkdir ssl/servercrldir
+ cp ssl/server.crl ssl/servercrldir/`openssl crl -hash -noout -in ssl/server.crl`.r0
+ cp ssl/root.crl ssl/servercrldir/`openssl crl -hash -noout -in ssl/root.crl`.r0
+ssl/clientcrldir: ssl/client.crl
+ mkdir ssl/clientcrldir
+ cp ssl/client.crl ssl/clientcrldir/`openssl crl -hash -noout -in ssl/client.crl`.r0
+ cp ssl/root.crl ssl/clientcrldir/`openssl crl -hash -noout -in ssl/root.crl`.r0
 
 .PHONY: sslfiles-clean
 sslfiles-clean:
  rm -f $(SSLFILES) ssl/client_ca.srl ssl/server_ca.srl ssl/client_ca-certindex* ssl/server_ca-certindex* ssl/root_ca-certindex* ssl/root_ca.srl ssl/temp_ca.crt ssl/temp_ca_signed.crt
+ rm -rf $(SSLDIRS)
 
 clean distclean maintainer-clean:
  rm -rf tmp_check
diff --git a/src/test/ssl/ssl/clientcrldir/9bb9e3c3.r0 b/src/test/ssl/ssl/clientcrldir/9bb9e3c3.r0
new file mode 100644
index 0000000000..a667680e04
--- /dev/null
+++ b/src/test/ssl/ssl/clientcrldir/9bb9e3c3.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBnjCBhzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3QgY2xpZW50IGNlcnRzFw0xODEx
+MjcxMzQwNTVaFw00NjA0MTQxMzQwNTVaMBQwEgIBAhcNMTgxMTI3MTM0MDU1WjAN
+BgkqhkiG9w0BAQsFAAOCAQEAXjLxA9Qc6gAudwUHBxMIq5EHBcuNEX5e3GNlkyNf
+8I0DtHTPfJPvmAG+i6lYz//hHmmjxK0dR2ucg79XgXI/6OpDqlxS/TG1Xv52wA1p
+xz6GaJ2hC8Lk4/vbJo/Rrzme2QsI7xqBWya0JWVrehttqhFxPzWA5wID8X7G4Kb4
+pjVnzqYzn8A9FBiV9t10oZg60aVLqt3kbyy+U3pefvjhj8NmQc7uyuVjWvYZA0vG
+nnDUo4EKJzHNIYLk+EfpzKWO2XAWBLOT9SyyNCeMuQ5p/2pdAt9jtWHenms2ajo9
+2iUsHS91e3TooP9yNYuNcN8/wXY6H2Xm+dCLcEnkcr7EEw==
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/clientcrldir/a3d11bff.r0 b/src/test/ssl/ssl/clientcrldir/a3d11bff.r0
new file mode 100644
index 0000000000..e879cf25a7
--- /dev/null
+++ b/src/test/ssl/ssl/clientcrldir/a3d11bff.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBhTBvMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm
+b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0xODExMjcx
+MzQwNTVaFw00NjA0MTQxMzQwNTVaMA0GCSqGSIb3DQEBCwUAA4IBAQB8OSDym4/a
+qbZOrZvOOhmKrd7AJSTgAadtdK0CX3v58Ym3EmZK7gQFdBuFCXnvbue/x6avZHgz
+4pYFlJmL0IiD4QuTzsoo+LzifrmTzteO9oEJNLd2bjfEnpE5Wdaw6Yuy2Xb5edy5
+lQhNZdc8w3FiXhPOEUAi7EbdfDwn4G/fvEjpzyVb2wCujDUUePUGGayjKIM4PUu4
+pixM6gt9FFL27l47lQ3g0PbvB3TnU3oqcB3Y17FjbxjFc6AsGXholNetoEE2/49E
+PEYzOH7/PtxlZUtoCqZM+741LuI6Q7z4/P2X/IY33lMy6Iiyc41C94l/P7fCkMLG
+AlO+O0a4SpYS
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/servercrldir/a3d11bff.r0 b/src/test/ssl/ssl/servercrldir/a3d11bff.r0
new file mode 100644
index 0000000000..e879cf25a7
--- /dev/null
+++ b/src/test/ssl/ssl/servercrldir/a3d11bff.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBhTBvMA0GCSqGSIb3DQEBCwUAMEAxPjA8BgNVBAMMNVRlc3Qgcm9vdCBDQSBm
+b3IgUG9zdGdyZVNRTCBTU0wgcmVncmVzc2lvbiB0ZXN0IHN1aXRlFw0xODExMjcx
+MzQwNTVaFw00NjA0MTQxMzQwNTVaMA0GCSqGSIb3DQEBCwUAA4IBAQB8OSDym4/a
+qbZOrZvOOhmKrd7AJSTgAadtdK0CX3v58Ym3EmZK7gQFdBuFCXnvbue/x6avZHgz
+4pYFlJmL0IiD4QuTzsoo+LzifrmTzteO9oEJNLd2bjfEnpE5Wdaw6Yuy2Xb5edy5
+lQhNZdc8w3FiXhPOEUAi7EbdfDwn4G/fvEjpzyVb2wCujDUUePUGGayjKIM4PUu4
+pixM6gt9FFL27l47lQ3g0PbvB3TnU3oqcB3Y17FjbxjFc6AsGXholNetoEE2/49E
+PEYzOH7/PtxlZUtoCqZM+741LuI6Q7z4/P2X/IY33lMy6Iiyc41C94l/P7fCkMLG
+AlO+O0a4SpYS
+-----END X509 CRL-----
diff --git a/src/test/ssl/ssl/servercrldir/a836cc2d.r0 b/src/test/ssl/ssl/servercrldir/a836cc2d.r0
new file mode 100644
index 0000000000..717951c26a
--- /dev/null
+++ b/src/test/ssl/ssl/servercrldir/a836cc2d.r0
@@ -0,0 +1,11 @@
+-----BEGIN X509 CRL-----
+MIIBnjCBhzANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDDDdUZXN0IENBIGZvciBQ
+b3N0Z3JlU1FMIFNTTCByZWdyZXNzaW9uIHRlc3Qgc2VydmVyIGNlcnRzFw0xODEx
+MjcxMzQwNTVaFw00NjA0MTQxMzQwNTVaMBQwEgIBBhcNMTgxMTI3MTM0MDU1WjAN
+BgkqhkiG9w0BAQsFAAOCAQEAbVuJXemxM6HLlIHGWlQvVmsmG4ZTQWiDnZjfmrND
+xB4XsvZNPXnFkjdBENDROrbDRwm60SJDW73AbDbfq1IXAzSpuEyuRz61IyYKo0wq
+nmObJtVdIu3bVlWIlDXaP5Emk3d7ouCj5f8Kyeb8gm4pL3N6e0eI63hCaS39hhE6
+RLGh9HU9ht1kKfgcTwmB5b2HTPb4M6z1AmSIaMVqZTjIspsUgNF2+GBm3fOnOaiZ
+SEXWtgjMRXiIHbtU0va3LhSH5OSW0mh+L9oGUQDYnyuudnWGpulhqIp4qVkJRDDu
+41HpD83dV2uRtBLvc25AFHj7kXBflbO3gvGZVPYf1zVghQ==
+-----END X509 CRL-----
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index fd2727b568..8b0787ce7f 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -13,7 +13,7 @@ use SSLServer;
 
 if ($ENV{with_openssl} eq 'yes')
 {
- plan tests => 93;
+ plan tests => 100;
 }
 else
 {
@@ -214,6 +214,12 @@ test_connect_fails(
  "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/client.crl",
  qr/SSL error/,
  "CRL belonging to a different CA");
+# The same for CRL directory, fails
+test_connect_fails(
+ $common_connstr,
+ "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/clientcrldir",
+ qr/SSL error/,
+ "directory CRL belonging to a different CA");
 
 # With the correct CRL, succeeds (this cert is not revoked)
 test_connect_ok(
@@ -221,6 +227,12 @@ test_connect_ok(
  "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/root+server.crl",
  "CRL with a non-revoked cert");
 
+# With the correct server CRL directory, succeeds (this cert is not revoked)
+test_connect_ok(
+ $common_connstr,
+ "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/servercrldir",
+ "HOGE directory CRL with a non-revoked cert");
+
 # Check that connecting with verify-full fails, when the hostname doesn't
 # match the hostname in the server's certificate.
 $common_connstr =
@@ -346,7 +358,12 @@ test_connect_fails(
  $common_connstr,
  "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/root+server.crl",
  qr/SSL error/,
- "does not connect with client-side CRL");
+ "does not connect with client-side CRL file");
+test_connect_fails(
+ $common_connstr,
+ "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/servercrldir",
+ qr/SSL error/,
+ "does not connect with client-side CRL directory");
 
 # pg_stat_ssl
 command_like(
@@ -545,6 +562,16 @@ test_connect_ok(
 test_connect_fails($common_connstr, "sslmode=require sslcert=ssl/client.crt",
  qr/SSL error/, "intermediate client certificate is missing");
 
+# test server-side CRL directory
+switch_server_cert($node, 'server-revoked', undef, 1);
+
+# revoked client cert
+test_connect_fails(
+ $common_connstr,
+ "user=ssltestuser sslcert=ssl/client-revoked.crt sslkey=ssl/client-revoked_tmp.key",
+ qr/SSL error/,
+ "certificate authorization fails with revoked client cert with server-side CRL directory");
+
 # clean up
 foreach my $key (@keys)
 {
diff --git a/src/test/ssl/t/SSLServer.pm b/src/test/ssl/t/SSLServer.pm
index 1e392b8fbf..5bc3bc91d5 100644
--- a/src/test/ssl/t/SSLServer.pm
+++ b/src/test/ssl/t/SSLServer.pm
@@ -151,6 +151,8 @@ sub configure_test_server_for_ssl
  copy_files("ssl/root+client_ca.crt", $pgdata);
  copy_files("ssl/root_ca.crt",        $pgdata);
  copy_files("ssl/root+client.crl",    $pgdata);
+ mkdir("$pgdata/clientcrldir");
+ copy_files("ssl/clientcrldir/*", "$pgdata/clientcrldir/");
 
  # Stop and restart server to load new listen_addresses.
  $node->restart;
@@ -168,6 +170,7 @@ sub switch_server_cert
  my $node     = $_[0];
  my $certfile = $_[1];
  my $cafile   = $_[2] || "root+client_ca";
+ my $crlfile  = ($_[3] ? "clientcrldir" : "root+client.crl");
  my $pgdata   = $node->data_dir;
 
  open my $sslconf, '>', "$pgdata/sslconfig.conf";
@@ -175,7 +178,7 @@ sub switch_server_cert
  print $sslconf "ssl_ca_file='$cafile.crt'\n";
  print $sslconf "ssl_cert_file='$certfile.crt'\n";
  print $sslconf "ssl_key_file='$certfile.key'\n";
- print $sslconf "ssl_crl_file='root+client.crl'\n";
+ print $sslconf "ssl_crl_file='$crlfile'\n";
  close $sslconf;
 
  $node->restart;
--
2.18.4