diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 57d95d2020..2f6821a45f 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -7685,23 +7685,35 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*)
If the server attempts to verify the identity of the
client by requesting the client's leaf certificate,
- libpq will send the certificates stored in
+ libpq will send the certificate(s) stored in
file ~/.postgresql/postgresql.crt in the user's home
directory. The certificates must chain to the root certificate trusted
by the server. A matching
private key file ~/.postgresql/postgresql.key must also
- be present. The private
- key file must not allow any access to world or group; achieve this by the
- command chmod 0600 ~/.postgresql/postgresql.key.
+ be present.
On Microsoft Windows these files are named
%APPDATA%\postgresql\postgresql.crt and
- %APPDATA%\postgresql\postgresql.key, and there
- is no special permissions check since the directory is presumed secure.
+ %APPDATA%\postgresql\postgresql.key.
The location of the certificate and key files can be overridden by the
- connection parameters sslcert and sslkey or the
+ connection parameters sslcert
+ and sslkey, or by the
environment variables PGSSLCERT and PGSSLKEY.
+
+ On Unix systems, the permissions on the private key file must disallow
+ any access to world or group; achieve this by a command such as
+ chmod 0600 ~/.postgresql/postgresql.key.
+ Alternatively, the file can be owned by root and have group read access
+ (that is, 0640 permissions). That setup is intended
+ for installations where certificate and key files are managed by the
+ operating system. The user of libpq should
+ then be made a member of the group that has access to those certificate
+ and key files. (On Microsoft Windows, there is no file permissions
+ check, since the %APPDATA%\postgresql directory is
+ presumed secure.)
+
+
The first certificate in postgresql.crt must be the
client's certificate because it must match the client's private key.
diff --git a/src/backend/libpq/be-secure-common.c b/src/backend/libpq/be-secure-common.c
index 94cdf4c887..7da0cfd1cf 100644
--- a/src/backend/libpq/be-secure-common.c
+++ b/src/backend/libpq/be-secure-common.c
@@ -143,6 +143,7 @@ check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart)
return false;
}
+ /* Key file must be a regular file */
if (!S_ISREG(buf.st_mode))
{
ereport(loglevel,
@@ -153,9 +154,19 @@ check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart)
}
/*
- * Refuse to load key files owned by users other than us or root.
+ * Refuse to load key files owned by users other than us or root, and
+ * require no public access to the key file. If the file is owned by us,
+ * require mode 0600 or less. If owned by root, require 0640 or less to
+ * allow read access through either our gid or a supplementary gid that
+ * allows us to read system-wide certificates.
*
- * XXX surely we can check this on Windows somehow, too.
+ * Note that similar checks are performed in
+ * src/interfaces/libpq/fe-secure-openssl.c so any changes here may need
+ * to be made there as well.
+ *
+ * Ideally we would do similar permissions checks on Windows, but it is
+ * not clear how that would work since Unix-style permissions may not be
+ * available.
*/
#if !defined(WIN32) && !defined(__CYGWIN__)
if (buf.st_uid != geteuid() && buf.st_uid != 0)
@@ -166,20 +177,7 @@ check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart)
ssl_key_file)));
return false;
}
-#endif
- /*
- * Require no public access to key file. If the file is owned by us,
- * require mode 0600 or less. If owned by root, require 0640 or less to
- * allow read access through our gid, or a supplementary gid that allows
- * to read system-wide certificates.
- *
- * XXX temporarily suppress check when on Windows, because there may not
- * be proper support for Unix-y file permissions. Need to think of a
- * reasonable check to apply on Windows. (See also the data directory
- * permission check in postmaster.c)
- */
-#if !defined(WIN32) && !defined(__CYGWIN__)
if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) ||
(buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)))
{
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index 987fe02419..7348a62e46 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -1187,11 +1187,45 @@ initialize_SSL(PGconn *conn)
fnbuf);
return -1;
}
-#ifndef WIN32
- if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
+
+ /* Key file must be a regular file */
+ if (!S_ISREG(buf.st_mode))
{
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
+ libpq_gettext("private key file \"%s\" is not a regular file"),
+ fnbuf);
+ return -1;
+ }
+
+ /*
+ * Refuse to load key files owned by users other than us or root, and
+ * require no public access to the key file. If the file is owned by
+ * us, require mode 0600 or less. If owned by root, require 0640 or
+ * less to allow read access through either our gid or a supplementary
+ * gid that allows us to read system-wide certificates.
+ *
+ * Note that similar checks are performed in
+ * src/backend/libpq/be-secure-common.c so any changes here may need
+ * to be made there as well.
+ *
+ * Ideally we would do similar permissions checks on Windows, but it
+ * is not clear how that would work since Unix-style permissions may
+ * not be available.
+ */
+#if !defined(WIN32) && !defined(__CYGWIN__)
+ if (buf.st_uid != geteuid() && buf.st_uid != 0)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("private key file \"%s\" must be owned by the current user or root\n"),
+ fnbuf);
+ return -1;
+ }
+
+ if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) ||
+ (buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)))
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("private key file \"%s\" has group or world access; file must have permissions u=rw (0600) or less if owned by the current user, or permissions u=rw,g=r (0640) or less if owned by root\n"),
fnbuf);
return -1;
}