Dear Hackers,
I would like to propose a different approach regarding the client side behavior in terms of working with the list of revoked certificates.
The problem that was discovered is that if a user, using psql, accidentally specifies an incorrect path to a crl file or crl directory, the client part of Postgres ignores the user's error and connects the client to the database whose certificate the client would, in theory, want to check whether the database server certificate has been revoked.
Regards,
- Michael
From 71dad6ef2f4eb11a388c54c1d6fdf8cc2ca26179 Mon Sep 17 00:00:00 2001 From: "Michael Kuptsov" <[email protected]> Date: Mon, 3 Aug 2026 11:13:28 +0700 Subject: Changing client-side behavior regarding Certificate Revocation Lists (CRL)
---
src/interfaces/libpq/fe-secure-openssl.c | 79 ++++++++++++++++++++++--
1 file changed, 73 insertions(+), 6 deletions(-)
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index 140cec0e003..1518840041d 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -987,10 +987,12 @@ initialize_SSL(PGconn *conn)
{
char *fname = NULL;
char *dname = NULL;
+ bool use_sslcrl = (conn->sslcrl && strlen(conn->sslcrl) > 0);
+ bool use_sslcrldir = (conn->sslcrldir && strlen(conn->sslcrldir) > 0);
- if (conn->sslcrl && strlen(conn->sslcrl) > 0)
+ if (use_sslcrl)
fname = conn->sslcrl;
- if (conn->sslcrldir && strlen(conn->sslcrldir) > 0)
+ if (use_sslcrldir)
dname = conn->sslcrldir;
/* defaults to use the default CRL file */
@@ -1000,16 +1002,81 @@ initialize_SSL(PGconn *conn)
fname = fnbuf;
}
+ if (use_sslcrl)
+ {
+ if (stat(fname, &buf) != 0)
+ {
+ libpq_append_conn_error(conn, "certificate revocation list file \"%s\" does not exist", fname);
+ SSL_CTX_free(SSL_context);
+ return -1;
+ }
+ if (!S_ISREG(buf.st_mode))
+ {
+ libpq_append_conn_error(conn, "certificate revocation list file \"%s\" is not a regular file", fname);
+ SSL_CTX_free(SSL_context);
+ return -1;
+ }
+ }
+
+ if (use_sslcrldir)
+ {
+ if (stat(dname, &buf) != 0)
+ {
+ libpq_append_conn_error(conn, "certificate revocation list directory \"%s\" does not exist", dname);
+ SSL_CTX_free(SSL_context);
+ return -1;
+ }
+ if (!S_ISDIR(buf.st_mode))
+ {
+ libpq_append_conn_error(conn, "certificate revocation list directory \"%s\" is not a directory", dname);
+ SSL_CTX_free(SSL_context);
+ return -1;
+ }
+ }
+
/* Set the flags to check against the complete CRL chain */
if ((fname || dname) &&
X509_STORE_load_locations(cvstore, fname, dname) == 1)
{
- X509_STORE_set_flags(cvstore,
- X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
+ if (X509_STORE_set_flags(cvstore,
+ X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL) != 1)
+ {
+ char *err = SSLerrmessage(ERR_get_error());
+ libpq_append_conn_error(conn, "could not set crl check flags: %s",err);
+ SSLerrfree(err);
+ SSL_CTX_free(SSL_context);
+ return -1;
+ }
}
+ else
+ {
+ char *err = SSLerrmessage(ERR_get_error());
+
+ if (use_sslcrl)
+ {
+ libpq_append_conn_error(conn, "could not load SSL certificate revocation list file \"%s\": %s", fname, err);
+ SSLerrfree(err);
+ SSL_CTX_free(SSL_context);
+ return -1;
+ }
+ else if (use_sslcrldir)
+ {
+ libpq_append_conn_error(conn, "could not load SSL certificate revocation list directory \"%s\": %s", dname, err);
+ SSLerrfree(err);
+ SSL_CTX_free(SSL_context);
+ return -1;
+ }
- /* if not found, silently ignore; we do not require CRL */
- ERR_clear_error();
+ ERR_clear_error();
+ }
+ }
+ else
+ {
+ char *err = SSLerrmessage(ERR_get_error());
+ libpq_append_conn_error(conn, "could not get cert store: %s", err);
+ SSLerrfree(err);
+ SSL_CTX_free(SSL_context);
+ return -1;
}
have_rootcert = true;
}
--
2.53.0
