Skip to content

Commit 2a1f846

Browse files
committed
Allow root-owned SSL private keys in libpq, not only the backend.
This change makes libpq apply the same private-key-file ownership and permissions checks that we have used in the backend since commit 9a83564. Namely, that the private key can be owned by either the current user or root (with different file permissions allowed in the two cases). This allows system-wide management of key files, which is just as sensible on the client side as the server, particularly when the client is itself some application daemon. Sync the comments about this between libpq and the backend, too. Back-patch of a59c795 and 50f0347 into all supported branches. David Steele Discussion: https://postgr.es/m/f4b7bc55-97ac-9e69-7398-335e212f7743@pgmasters.net
1 parent ac910bb commit 2a1f846

File tree

3 files changed

+69
-25
lines changed

3 files changed

+69
-25
lines changed

doc/src/sgml/libpq.sgml

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8397,23 +8397,35 @@ ldap://ldap.acme.com/cn=dbserver,cn=hosts?pgconnectinfo?base?(objectclass=*)
83978397
<para>
83988398
If the server attempts to verify the identity of the
83998399
client by requesting the client's leaf certificate,
8400-
<application>libpq</application> will send the certificates stored in
8400+
<application>libpq</application> will send the certificate(s) stored in
84018401
file <filename>~/.postgresql/postgresql.crt</filename> in the user's home
84028402
directory. The certificates must chain to the root certificate trusted
84038403
by the server. A matching
84048404
private key file <filename>~/.postgresql/postgresql.key</filename> must also
8405-
be present. The private
8406-
key file must not allow any access to world or group; achieve this by the
8407-
command <command>chmod 0600 ~/.postgresql/postgresql.key</command>.
8405+
be present.
84088406
On Microsoft Windows these files are named
84098407
<filename>%APPDATA%\postgresql\postgresql.crt</filename> and
8410-
<filename>%APPDATA%\postgresql\postgresql.key</filename>, and there
8411-
is no special permissions check since the directory is presumed secure.
8408+
<filename>%APPDATA%\postgresql\postgresql.key</filename>.
84128409
The location of the certificate and key files can be overridden by the
8413-
connection parameters <literal>sslcert</literal> and <literal>sslkey</literal> or the
8410+
connection parameters <literal>sslcert</literal>
8411+
and <literal>sslkey</literal>, or by the
84148412
environment variables <envar>PGSSLCERT</envar> and <envar>PGSSLKEY</envar>.
84158413
</para>
84168414

8415+
<para>
8416+
On Unix systems, the permissions on the private key file must disallow
8417+
any access to world or group; achieve this by a command such as
8418+
<command>chmod 0600 ~/.postgresql/postgresql.key</command>.
8419+
Alternatively, the file can be owned by root and have group read access
8420+
(that is, <literal>0640</literal> permissions). That setup is intended
8421+
for installations where certificate and key files are managed by the
8422+
operating system. The user of <application>libpq</application> should
8423+
then be made a member of the group that has access to those certificate
8424+
and key files. (On Microsoft Windows, there is no file permissions
8425+
check, since the <filename>%APPDATA%\postgresql</filename> directory is
8426+
presumed secure.)
8427+
</para>
8428+
84178429
<para>
84188430
The first certificate in <filename>postgresql.crt</filename> must be the
84198431
client's certificate because it must match the client's private key.

src/backend/libpq/be-secure-common.c

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart)
143143
return false;
144144
}
145145

146+
/* Key file must be a regular file */
146147
if (!S_ISREG(buf.st_mode))
147148
{
148149
ereport(loglevel,
@@ -153,9 +154,19 @@ check_ssl_key_file_permissions(const char *ssl_key_file, bool isServerStart)
153154
}
154155

155156
/*
156-
* Refuse to load key files owned by users other than us or root.
157+
* Refuse to load key files owned by users other than us or root, and
158+
* require no public access to the key file. If the file is owned by us,
159+
* require mode 0600 or less. If owned by root, require 0640 or less to
160+
* allow read access through either our gid or a supplementary gid that
161+
* allows us to read system-wide certificates.
157162
*
158-
* XXX surely we can check this on Windows somehow, too.
163+
* Note that similar checks are performed in
164+
* src/interfaces/libpq/fe-secure-openssl.c so any changes here may need
165+
* to be made there as well.
166+
*
167+
* Ideally we would do similar permissions checks on Windows, but it is
168+
* not clear how that would work since Unix-style permissions may not be
169+
* available.
159170
*/
160171
#if !defined(WIN32) && !defined(__CYGWIN__)
161172
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)
166177
ssl_key_file)));
167178
return false;
168179
}
169-
#endif
170180

171-
/*
172-
* Require no public access to key file. If the file is owned by us,
173-
* require mode 0600 or less. If owned by root, require 0640 or less to
174-
* allow read access through our gid, or a supplementary gid that allows
175-
* to read system-wide certificates.
176-
*
177-
* XXX temporarily suppress check when on Windows, because there may not
178-
* be proper support for Unix-y file permissions. Need to think of a
179-
* reasonable check to apply on Windows. (See also the data directory
180-
* permission check in postmaster.c)
181-
*/
182-
#if !defined(WIN32) && !defined(__CYGWIN__)
183181
if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) ||
184182
(buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)))
185183
{

src/interfaces/libpq/fe-secure-openssl.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,11 +1229,45 @@ initialize_SSL(PGconn *conn)
12291229
fnbuf);
12301230
return -1;
12311231
}
1232-
#ifndef WIN32
1233-
if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
1232+
1233+
/* Key file must be a regular file */
1234+
if (!S_ISREG(buf.st_mode))
1235+
{
1236+
appendPQExpBuffer(&conn->errorMessage,
1237+
libpq_gettext("private key file \"%s\" is not a regular file"),
1238+
fnbuf);
1239+
return -1;
1240+
}
1241+
1242+
/*
1243+
* Refuse to load key files owned by users other than us or root, and
1244+
* require no public access to the key file. If the file is owned by
1245+
* us, require mode 0600 or less. If owned by root, require 0640 or
1246+
* less to allow read access through either our gid or a supplementary
1247+
* gid that allows us to read system-wide certificates.
1248+
*
1249+
* Note that similar checks are performed in
1250+
* src/backend/libpq/be-secure-common.c so any changes here may need
1251+
* to be made there as well.
1252+
*
1253+
* Ideally we would do similar permissions checks on Windows, but it
1254+
* is not clear how that would work since Unix-style permissions may
1255+
* not be available.
1256+
*/
1257+
#if !defined(WIN32) && !defined(__CYGWIN__)
1258+
if (buf.st_uid != geteuid() && buf.st_uid != 0)
1259+
{
1260+
appendPQExpBuffer(&conn->errorMessage,
1261+
libpq_gettext("private key file \"%s\" must be owned by the current user or root\n"),
1262+
fnbuf);
1263+
return -1;
1264+
}
1265+
1266+
if ((buf.st_uid == geteuid() && buf.st_mode & (S_IRWXG | S_IRWXO)) ||
1267+
(buf.st_uid == 0 && buf.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)))
12341268
{
12351269
appendPQExpBuffer(&conn->errorMessage,
1236-
libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
1270+
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"),
12371271
fnbuf);
12381272
return -1;
12391273
}

0 commit comments

Comments
 (0)