controlling the location of server-side SSL files
I think I would like to have a set of GUC parameters to control the
location of the server-side SSL files. In a setup that has all the
other configuration files under /etc, the SSL files ought to go there as
well. (For comparison, most email and web servers keep them there.)
Having them in the data directory keeps requiring a bunch of special
treatment in the configuration management set up, and during backup and
recovery. Any concerns about that?
On Jan 2, 2012 5:33 AM, "Peter Eisentraut" <peter_e@gmx.net> wrote:
I think I would like to have a set of GUC parameters to control the
location of the server-side SSL files. In a setup that has all the
other configuration files under /etc, the SSL files ought to go there as
well. (For comparison, most email and web servers keep them there.)
Having them in the data directory keeps requiring a bunch of special
treatment in the configuration management set up, and during backup and
recovery. Any concerns about that?
While I personally prefer keeping them in the data directory for backup
reasons (clearly different backup reasons than yours though), i agree we
should have such an option - for consistency if nothing else.
Were you thinking one option pointing to a directory or one option per
file?
/Magnus
On mån, 2012-01-02 at 15:47 +0100, Magnus Hagander wrote:
Were you thinking one option pointing to a directory or one option per
file?
One option per file:
ssl_cert_file
ssl_key_file
ssl_ca_file
ssl_crl_file
This is very similar to the configuration of, for example, Apache,
Dovecot, Postfix, so it should be quite familiar to administrators. It
also mirrors that we have libpq options to set these things on the
client side. (We use the term "root certificate" in libpq, but I think
"CA" is more commonly used in these situations. Not sure.)
Peter Eisentraut <peter_e@gmx.net> writes:
On mån, 2012-01-02 at 15:47 +0100, Magnus Hagander wrote:
Were you thinking one option pointing to a directory or one option per
file?
One option per file:
That seems like serious overkill. Why not one option specifying the
directory? What use-case is there for letting them be in different
directories, let alone letting the DBA choose random names for each one?
regards, tom lane
On mån, 2012-01-02 at 23:42 -0500, Tom Lane wrote:
Peter Eisentraut <peter_e@gmx.net> writes:
On mån, 2012-01-02 at 15:47 +0100, Magnus Hagander wrote:
Were you thinking one option pointing to a directory or one option per
file?One option per file:
That seems like serious overkill. Why not one option specifying the
directory? What use-case is there for letting them be in different
directories, let alone letting the DBA choose random names for each one?
Several consistency reasons:
- We provide the same per-file options in libpq.
- Indeed, if you use something like dblink or plproxy, these might even
point to the same files.
- We also have settings for hba_file and ident_file that point to a
file.
- All other daemons with SSL support known to me, such as mail and web
servers, have per-file options.
Also some practical reasons:
- Yes, choosing random names is important. We have local naming
schemes. And I would rather have a descriptive file name for the CA
than having them all named root.crt, and if I want to know which one it
is I have to look inside the file.
- You might not want all of the files in the same directory. CA and CRL
might live elsewhere, for example.
On Tue, Jan 3, 2012 at 6:25 PM, Peter Eisentraut <peter_e@gmx.net> wrote:
On mån, 2012-01-02 at 23:42 -0500, Tom Lane wrote:
Peter Eisentraut <peter_e@gmx.net> writes:
On mån, 2012-01-02 at 15:47 +0100, Magnus Hagander wrote:
Were you thinking one option pointing to a directory or one option per
file?One option per file:
That seems like serious overkill. Why not one option specifying the
directory? What use-case is there for letting them be in different
directories, let alone letting the DBA choose random names for each one?[ reasons ]
I agree with these reasons. We don't get charged $0.50 per GUC, so
there's no particular reason to contort things to have fewer of them.
It's nice where it's possible, of course, but not when it makes people
contort things to support the way we think our users should lay out
their filesystem.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Tue, Jan 3, 2012 at 6:25 PM, Peter Eisentraut <peter_e@gmx.net> wrote:
[ reasons ]
I agree with these reasons. We don't get charged $0.50 per GUC, so
there's no particular reason to contort things to have fewer of them.
Well, there definitely is a distributed cost to each additional GUC.
Peter's given what are probably adequate reasons to add several of them
here, but that doesn't mean we should not ask the question whether each
new GUC is really necessary.
regards, tom lane
On Tue, Jan 3, 2012 at 9:38 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
On Tue, Jan 3, 2012 at 6:25 PM, Peter Eisentraut <peter_e@gmx.net> wrote:
[ reasons ]
I agree with these reasons. We don't get charged $0.50 per GUC, so
there's no particular reason to contort things to have fewer of them.Well, there definitely is a distributed cost to each additional GUC.
Peter's given what are probably adequate reasons to add several of them
here, but that doesn't mean we should not ask the question whether each
new GUC is really necessary.
No argument. I'm merely saying that I think the rationale for these
GUCs is solid enough to justify their existence.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On mån, 2012-01-02 at 06:32 +0200, Peter Eisentraut wrote:
I think I would like to have a set of GUC parameters to control the
location of the server-side SSL files.
Here is the patch for this.
One thing that is perhaps worth thinking about: Currently, we just
ignore missing root.crt and root.crl files. With this patch, we still
do this, even if the user has given a specific nondefault location.
That seems a bit odd, but I can't think of a simple way to do it better.
Attachments:
ssl-files-guc.patchtext/x-patch; charset=UTF-8; name=ssl-files-guc.patchDownload
diff --git i/doc/src/sgml/config.sgml w/doc/src/sgml/config.sgml
index 0cc3296..519715f 100644
--- i/doc/src/sgml/config.sgml
+++ w/doc/src/sgml/config.sgml
@@ -668,6 +668,66 @@ SET ENABLE_SEQSCAN TO OFF;
</listitem>
</varlistentry>
+ <varlistentry id="guc-ssl-ca-file" xreflabel="ssl_ca_file">
+ <term><varname>ssl_ca_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>ssl_ca_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the name of the file containing the SSL server certificate
+ authority. The default is <filename>root.crt</filename>. Relative
+ paths are relative to the data directory. This parameter can only be
+ set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-ssl-cert-file" xreflabel="ssl_cert_file">
+ <term><varname>ssl_cert_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>ssl_cert_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the name of the file containing the SSL server certificate.
+ The default is <filename>server.crt</filename>. Relative paths are
+ relative to the data directory. This parameter can only be set at
+ server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-ssl-crl-file" xreflabel="ssl_crl_file">
+ <term><varname>ssl_crl_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>ssl_crl_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the name of the file containing the SSL server certificate
+ revocation list. The default is <filename>root.crl</filename>.
+ Relative paths are relative to the data directory. This parameter can
+ only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-ssl-key-file" xreflabel="ssl_key_file">
+ <term><varname>ssl_key_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>ssl_key_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the name of the file containing the SSL server private key.
+ The default is <filename>server.key</filename>. Relative paths are
+ relative to the data directory. This parameter can only be set at
+ server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-ssl-renegotiation-limit" xreflabel="ssl_renegotiation_limit">
<term><varname>ssl_renegotiation_limit</varname> (<type>integer</type>)</term>
<indexterm>
diff --git i/doc/src/sgml/runtime.sgml w/doc/src/sgml/runtime.sgml
index 1c3a9c8..a855279 100644
--- i/doc/src/sgml/runtime.sgml
+++ w/doc/src/sgml/runtime.sgml
@@ -1831,10 +1831,8 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
SSL certificates and make sure that clients check the server's certificate.
To do that, the server
must be configured to accept only <literal>hostssl</> connections (<xref
- linkend="auth-pg-hba-conf">) and have SSL
- <filename>server.key</filename> (key) and
- <filename>server.crt</filename> (certificate) files (<xref
- linkend="ssl-tcp">). The TCP client must connect using
+ linkend="auth-pg-hba-conf">) and have SSL key and certificate files
+ (<xref linkend="ssl-tcp">). The TCP client must connect using
<literal>sslmode=verify-ca</> or
<literal>verify-full</> and have the appropriate root certificate
file installed (<xref linkend="libpq-connect">).
@@ -2053,10 +2051,12 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
</note>
<para>
- To start in <acronym>SSL</> mode, the files <filename>server.crt</>
- and <filename>server.key</> must exist in the server's data directory.
- These files should contain the server certificate and private key,
- respectively.
+ To start in <acronym>SSL</> mode, files containing the server certificate
+ and private key must exist. By default, these files are expected to be
+ named <filename>server.crt</> and <filename>server.key</>, respectively, in
+ the server's data directory, but other names and locations can be specified
+ using the configuration parameters <xref linkend="guc-ssl-cert-file">
+ and <xref linkend="guc-ssl-key-file">.
On Unix systems, the permissions on <filename>server.key</filename> must
disallow any access to world or group; achieve this by the command
<command>chmod 0600 server.key</command>.
@@ -2144,27 +2144,27 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
<tbody>
<row>
- <entry><filename>$PGDATA/server.crt</></entry>
+ <entry><xref linkend="guc-ssl-cert-file"> (<filename>$PGDATA/server.crt</>)</entry>
<entry>server certificate</entry>
<entry>sent to client to indicate server's identity</entry>
</row>
<row>
- <entry><filename>$PGDATA/server.key</></entry>
+ <entry><xref linkend="guc-ssl-key-file"> (<filename>$PGDATA/server.key</>)</entry>
<entry>server private key</entry>
<entry>proves server certificate was sent by the owner; does not indicate
certificate owner is trustworthy</entry>
</row>
<row>
- <entry><filename>$PGDATA/root.crt</></entry>
+ <entry><xref linkend="guc-ssl-ca-file"> (<filename>$PGDATA/root.crt</>)</entry>
<entry>trusted certificate authorities</entry>
<entry>checks that client certificate is
signed by a trusted certificate authority</entry>
</row>
<row>
- <entry><filename>$PGDATA/root.crl</></entry>
+ <entry><xref linkend="guc-ssl-crl-file"> (<filename>$PGDATA/root.crl</>)</entry>
<entry>certificates revoked by certificate authorities</entry>
<entry>client certificate must not be on this list</entry>
</row>
@@ -2176,6 +2176,7 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
<para>
The files <filename>server.key</>, <filename>server.crt</>,
<filename>root.crt</filename>, and <filename>root.crl</filename>
+ (or their configured alternative names)
are only examined during server start; so you must restart
the server for changes in them to take effect.
</para>
diff --git i/src/backend/libpq/be-secure.c w/src/backend/libpq/be-secure.c
index e35df73..1e34e56 100644
--- i/src/backend/libpq/be-secure.c
+++ w/src/backend/libpq/be-secure.c
@@ -77,10 +77,10 @@
#ifdef USE_SSL
-#define ROOT_CERT_FILE "root.crt"
-#define ROOT_CRL_FILE "root.crl"
-#define SERVER_CERT_FILE "server.crt"
-#define SERVER_PRIVATE_KEY_FILE "server.key"
+char *ssl_cert_file;
+char *ssl_key_file;
+char *ssl_ca_file;
+char *ssl_crl_file;
static DH *load_dh_file(int keylength);
static DH *load_dh_buffer(const char *, size_t);
@@ -746,17 +746,17 @@ initialize_SSL(void)
* Load and verify server's certificate and private key
*/
if (SSL_CTX_use_certificate_chain_file(SSL_context,
- SERVER_CERT_FILE) != 1)
+ ssl_cert_file) != 1)
ereport(FATAL,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not load server certificate file \"%s\": %s",
- SERVER_CERT_FILE, SSLerrmessage())));
+ ssl_cert_file, SSLerrmessage())));
- if (stat(SERVER_PRIVATE_KEY_FILE, &buf) != 0)
+ if (stat(ssl_key_file, &buf) != 0)
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not access private key file \"%s\": %m",
- SERVER_PRIVATE_KEY_FILE)));
+ ssl_key_file)));
/*
* Require no public access to key file.
@@ -771,16 +771,16 @@ initialize_SSL(void)
ereport(FATAL,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("private key file \"%s\" has group or world access",
- SERVER_PRIVATE_KEY_FILE),
+ ssl_key_file),
errdetail("Permissions should be u=rw (0600) or less.")));
#endif
if (SSL_CTX_use_PrivateKey_file(SSL_context,
- SERVER_PRIVATE_KEY_FILE,
+ ssl_key_file,
SSL_FILETYPE_PEM) != 1)
ereport(FATAL,
(errmsg("could not load private key file \"%s\": %s",
- SERVER_PRIVATE_KEY_FILE, SSLerrmessage())));
+ ssl_key_file, SSLerrmessage())));
if (SSL_CTX_check_private_key(SSL_context) != 1)
ereport(FATAL,
@@ -802,7 +802,7 @@ initialize_SSL(void)
*/
ssl_loaded_verify_locations = false;
- if (access(ROOT_CERT_FILE, R_OK) != 0)
+ if (access(ssl_ca_file, R_OK) != 0)
{
/*
* If root certificate file simply not found, don't log an error here,
@@ -813,10 +813,10 @@ initialize_SSL(void)
if (errno != ENOENT)
ereport(FATAL,
(errmsg("could not access root certificate file \"%s\": %m",
- ROOT_CERT_FILE)));
+ ssl_ca_file)));
}
- else if (SSL_CTX_load_verify_locations(SSL_context, ROOT_CERT_FILE, NULL) != 1 ||
- (root_cert_list = SSL_load_client_CA_file(ROOT_CERT_FILE)) == NULL)
+ else if (SSL_CTX_load_verify_locations(SSL_context, ssl_ca_file, NULL) != 1 ||
+ (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL)
{
/*
* File was there, but we could not load it. This means the file is
@@ -824,7 +824,7 @@ initialize_SSL(void)
*/
ereport(FATAL,
(errmsg("could not load root certificate file \"%s\": %s",
- ROOT_CERT_FILE, SSLerrmessage())));
+ ssl_ca_file, SSLerrmessage())));
}
else
{
@@ -838,7 +838,7 @@ initialize_SSL(void)
if (cvstore)
{
/* Set the flags to check against the complete CRL chain */
- if (X509_STORE_load_locations(cvstore, ROOT_CRL_FILE, NULL) == 1)
+ if (X509_STORE_load_locations(cvstore, ssl_crl_file, NULL) == 1)
{
/* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
#ifdef X509_V_FLAG_CRL_CHECK
@@ -847,7 +847,7 @@ initialize_SSL(void)
#else
ereport(LOG,
(errmsg("SSL certificate revocation list file \"%s\" ignored",
- ROOT_CRL_FILE),
+ ssl_crl_file),
errdetail("SSL library does not support certificate revocation lists.")));
#endif
}
@@ -856,7 +856,7 @@ initialize_SSL(void)
/* Not fatal - we do not require CRL */
ereport(LOG,
(errmsg("SSL certificate revocation list file \"%s\" not found, skipping: %s",
- ROOT_CRL_FILE, SSLerrmessage()),
+ ssl_crl_file, SSLerrmessage()),
errdetail("Certificates will not be checked against revocation list.")));
}
diff --git i/src/backend/utils/misc/guc.c w/src/backend/utils/misc/guc.c
index 5c910dd..11006ea 100644
--- i/src/backend/utils/misc/guc.c
+++ w/src/backend/utils/misc/guc.c
@@ -39,6 +39,7 @@
#include "funcapi.h"
#include "libpq/auth.h"
#include "libpq/be-fsstubs.h"
+#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "optimizer/cost.h"
@@ -2961,6 +2962,46 @@ static struct config_string ConfigureNamesString[] =
},
{
+ {"ssl_cert_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ gettext_noop("Location of the SSL server certificate file."),
+ NULL
+ },
+ &ssl_cert_file,
+ "server.crt",
+ NULL, NULL, NULL
+ },
+
+ {
+ {"ssl_key_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ gettext_noop("Location of the SSL server private key file."),
+ NULL
+ },
+ &ssl_key_file,
+ "server.key",
+ NULL, NULL, NULL
+ },
+
+ {
+ {"ssl_ca_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ gettext_noop("Location of the SSL certificate authority file."),
+ NULL
+ },
+ &ssl_ca_file,
+ "root.crt",
+ NULL, NULL, NULL
+ },
+
+ {
+ {"ssl_crl_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ gettext_noop("Location of the SSL certificate revocation list file."),
+ NULL
+ },
+ &ssl_crl_file,
+ "root.crl",
+ NULL, NULL, NULL
+ },
+
+ {
{"stats_temp_directory", PGC_SIGHUP, STATS_COLLECTOR,
gettext_noop("Writes temporary statistics files to the specified directory."),
NULL,
diff --git i/src/backend/utils/misc/postgresql.conf.sample w/src/backend/utils/misc/postgresql.conf.sample
index 315db46..658c293 100644
--- i/src/backend/utils/misc/postgresql.conf.sample
+++ w/src/backend/utils/misc/postgresql.conf.sample
@@ -81,6 +81,10 @@
#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers
# (change requires restart)
#ssl_renegotiation_limit = 512MB # amount of data between renegotiations
+#ssl_cert_file = 'server.crt' # (change requires restart)
+#ssl_key_file = 'server.key' # (change requires restart)
+#ssl_ca_file = 'root.crt' # (change requires restart)
+#ssl_crl_file = 'root.crl' # (change requires restart)
#password_encryption = on
#db_user_namespace = off
diff --git i/src/include/libpq/libpq.h w/src/include/libpq/libpq.h
index a4ef7b3..7083cd8 100644
--- i/src/include/libpq/libpq.h
+++ w/src/include/libpq/libpq.h
@@ -70,6 +70,11 @@ extern void pq_endcopyout(bool errorAbort);
/*
* prototypes for functions in be-secure.c
*/
+extern char *ssl_cert_file;
+extern char *ssl_key_file;
+extern char *ssl_ca_file;
+extern char *ssl_crl_file;
+
extern int secure_initialize(void);
extern bool secure_loaded_verify_locations(void);
extern void secure_destroy(void);
On Sat, Jan 14, 2012 at 8:40 AM, Peter Eisentraut <peter_e@gmx.net> wrote:
On mån, 2012-01-02 at 06:32 +0200, Peter Eisentraut wrote:
I think I would like to have a set of GUC parameters to control the
location of the server-side SSL files.Here is the patch for this.
One thing that is perhaps worth thinking about: Currently, we just
ignore missing root.crt and root.crl files. With this patch, we still
do this, even if the user has given a specific nondefault location.
That seems a bit odd, but I can't think of a simple way to do it better.
There's a review in the CF app for this finding only minor issues, so
I'm marking this patch therein as "Ready for Committer".
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On tor, 2012-01-19 at 15:44 -0500, Robert Haas wrote:
On Sat, Jan 14, 2012 at 8:40 AM, Peter Eisentraut <peter_e@gmx.net> wrote:
On mån, 2012-01-02 at 06:32 +0200, Peter Eisentraut wrote:
I think I would like to have a set of GUC parameters to control the
location of the server-side SSL files.Here is the patch for this.
One thing that is perhaps worth thinking about: Currently, we just
ignore missing root.crt and root.crl files. With this patch, we still
do this, even if the user has given a specific nondefault location.
That seems a bit odd, but I can't think of a simple way to do it better.There's a review in the CF app for this finding only minor issues, so
I'm marking this patch therein as "Ready for Committer".
OK, no one had any concerns about the missing file behavior I described
above? If not, then I'll commit it soon.
On tis, 2012-01-24 at 22:05 +0200, Peter Eisentraut wrote:
One thing that is perhaps worth thinking about: Currently, we just
ignore missing root.crt and root.crl files. With this patch, we still
do this, even if the user has given a specific nondefault location.
That seems a bit odd, but I can't think of a simple way to do it better.There's a review in the CF app for this finding only minor issues, so
I'm marking this patch therein as "Ready for Committer".OK, no one had any concerns about the missing file behavior I
described above? If not, then I'll commit it soon.
I'm still worried about this. If we ignore a missing root.crt, then the
effect is that authentication and certificate verification might fail,
which would be annoying, but you'd notice it soon enough. But if we
ignore a missing root.crl, we are creating a security hole.
My best idea at the moment is that we should set these parameters to
empty by default, and make users point them to existing files if they
want to use that functionality. Comments?
On Tuesday, February 7, 2012, Peter Eisentraut wrote:
On tis, 2012-01-24 at 22:05 +0200, Peter Eisentraut wrote:
One thing that is perhaps worth thinking about: Currently, we just
ignore missing root.crt and root.crl files. With this patch, westill
do this, even if the user has given a specific nondefault location.
That seems a bit odd, but I can't think of a simple way to do itbetter.
There's a review in the CF app for this finding only minor issues, so
I'm marking this patch therein as "Ready for Committer".OK, no one had any concerns about the missing file behavior I
described above? If not, then I'll commit it soon.I'm still worried about this. If we ignore a missing root.crt, then the
effect is that authentication and certificate verification might fail,
which would be annoying, but you'd notice it soon enough. But if we
ignore a missing root.crl, we are creating a security hole.
Yes, ignoring a missing file in a security context is definitely not good.
It should throw an error.
We have a few bad defaults from the old days around SSL for this, but if it
requires breaking backwards compatibility to get it right, I think we
should still do it.
My best idea at the moment is that we should set these parameters to
empty by default, and make users point them to existing files if they
want to use that functionality. Comments?
+1. Anybody who actually cares about setting up security is likely not
going to rely on defaults anyway - and is certainly going to review
whatever they are. So there should be no big problem there.
//Magnus
--
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
On ons, 2012-02-08 at 09:16 +0100, Magnus Hagander wrote:
My best idea at the moment is that we should set these parameters to
empty by default, and make users point them to existing files if they
want to use that functionality. Comments?+1. Anybody who actually cares about setting up security is likely not
going to rely on defaults anyway - and is certainly going to review
whatever they are. So there should be no big problem there.
Updated patch to reflect this.
Attachments:
ssl-files-guc.patchtext/x-patch; charset=UTF-8; name=ssl-files-guc.patchDownload
*** i/doc/src/sgml/config.sgml
--- w/doc/src/sgml/config.sgml
***************
*** 668,673 **** SET ENABLE_SEQSCAN TO OFF;
--- 668,737 ----
</listitem>
</varlistentry>
+ <varlistentry id="guc-ssl-ca-file" xreflabel="ssl_ca_file">
+ <term><varname>ssl_ca_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>ssl_ca_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the name of the file containing the SSL server certificate
+ authority (CA). The default is empty, meaning no CA file is loaded,
+ and client certificate verification is not performed. (In previous
+ releases of PostgreSQL, the name of this file was hard-coded
+ as <filename>root.crt</filename>.) Relative paths are relative to the
+ data directory. This parameter can only be set at server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-ssl-cert-file" xreflabel="ssl_cert_file">
+ <term><varname>ssl_cert_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>ssl_cert_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the name of the file containing the SSL server certificate.
+ The default is <filename>server.crt</filename>. Relative paths are
+ relative to the data directory. This parameter can only be set at
+ server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-ssl-crl-file" xreflabel="ssl_crl_file">
+ <term><varname>ssl_crl_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>ssl_crl_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the name of the file containing the SSL server certificate
+ revocation list (CRL). The default is empty, meaning no CRL file is
+ loaded. (In previous releases of PostgreSQL, the name of this file was
+ hard-coded as <filename>root.crl</filename>.) Relative paths are
+ relative to the data directory. This parameter can only be set at
+ server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-ssl-key-file" xreflabel="ssl_key_file">
+ <term><varname>ssl_key_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>ssl_key_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies the name of the file containing the SSL server private key.
+ The default is <filename>server.key</filename>. Relative paths are
+ relative to the data directory. This parameter can only be set at
+ server start.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-ssl-renegotiation-limit" xreflabel="ssl_renegotiation_limit">
<term><varname>ssl_renegotiation_limit</varname> (<type>integer</type>)</term>
<indexterm>
*** i/doc/src/sgml/runtime.sgml
--- w/doc/src/sgml/runtime.sgml
***************
*** 1831,1840 **** pg_dumpall -p 5432 | psql -d postgres -p 5433
SSL certificates and make sure that clients check the server's certificate.
To do that, the server
must be configured to accept only <literal>hostssl</> connections (<xref
! linkend="auth-pg-hba-conf">) and have SSL
! <filename>server.key</filename> (key) and
! <filename>server.crt</filename> (certificate) files (<xref
! linkend="ssl-tcp">). The TCP client must connect using
<literal>sslmode=verify-ca</> or
<literal>verify-full</> and have the appropriate root certificate
file installed (<xref linkend="libpq-connect">).
--- 1831,1838 ----
SSL certificates and make sure that clients check the server's certificate.
To do that, the server
must be configured to accept only <literal>hostssl</> connections (<xref
! linkend="auth-pg-hba-conf">) and have SSL key and certificate files
! (<xref linkend="ssl-tcp">). The TCP client must connect using
<literal>sslmode=verify-ca</> or
<literal>verify-full</> and have the appropriate root certificate
file installed (<xref linkend="libpq-connect">).
***************
*** 2053,2062 **** pg_dumpall -p 5432 | psql -d postgres -p 5433
</note>
<para>
! To start in <acronym>SSL</> mode, the files <filename>server.crt</>
! and <filename>server.key</> must exist in the server's data directory.
! These files should contain the server certificate and private key,
! respectively.
On Unix systems, the permissions on <filename>server.key</filename> must
disallow any access to world or group; achieve this by the command
<command>chmod 0600 server.key</command>.
--- 2051,2062 ----
</note>
<para>
! To start in <acronym>SSL</> mode, files containing the server certificate
! and private key must exist. By default, these files are expected to be
! named <filename>server.crt</> and <filename>server.key</>, respectively, in
! the server's data directory, but other names and locations can be specified
! using the configuration parameters <xref linkend="guc-ssl-cert-file">
! and <xref linkend="guc-ssl-key-file">.
On Unix systems, the permissions on <filename>server.key</filename> must
disallow any access to world or group; achieve this by the command
<command>chmod 0600 server.key</command>.
***************
*** 2144,2170 **** pg_dumpall -p 5432 | psql -d postgres -p 5433
<tbody>
<row>
! <entry><filename>$PGDATA/server.crt</></entry>
<entry>server certificate</entry>
<entry>sent to client to indicate server's identity</entry>
</row>
<row>
! <entry><filename>$PGDATA/server.key</></entry>
<entry>server private key</entry>
<entry>proves server certificate was sent by the owner; does not indicate
certificate owner is trustworthy</entry>
</row>
<row>
! <entry><filename>$PGDATA/root.crt</></entry>
<entry>trusted certificate authorities</entry>
<entry>checks that client certificate is
signed by a trusted certificate authority</entry>
</row>
<row>
! <entry><filename>$PGDATA/root.crl</></entry>
<entry>certificates revoked by certificate authorities</entry>
<entry>client certificate must not be on this list</entry>
</row>
--- 2144,2170 ----
<tbody>
<row>
! <entry><xref linkend="guc-ssl-cert-file"> (<filename>$PGDATA/server.crt</>)</entry>
<entry>server certificate</entry>
<entry>sent to client to indicate server's identity</entry>
</row>
<row>
! <entry><xref linkend="guc-ssl-key-file"> (<filename>$PGDATA/server.key</>)</entry>
<entry>server private key</entry>
<entry>proves server certificate was sent by the owner; does not indicate
certificate owner is trustworthy</entry>
</row>
<row>
! <entry><xref linkend="guc-ssl-ca-file"> (<filename>$PGDATA/root.crt</>)</entry>
<entry>trusted certificate authorities</entry>
<entry>checks that client certificate is
signed by a trusted certificate authority</entry>
</row>
<row>
! <entry><xref linkend="guc-ssl-crl-file"> (<filename>$PGDATA/root.crl</>)</entry>
<entry>certificates revoked by certificate authorities</entry>
<entry>client certificate must not be on this list</entry>
</row>
***************
*** 2176,2181 **** pg_dumpall -p 5432 | psql -d postgres -p 5433
--- 2176,2182 ----
<para>
The files <filename>server.key</>, <filename>server.crt</>,
<filename>root.crt</filename>, and <filename>root.crl</filename>
+ (or their configured alternative names)
are only examined during server start; so you must restart
the server for changes in them to take effect.
</para>
*** i/src/backend/libpq/be-secure.c
--- w/src/backend/libpq/be-secure.c
***************
*** 77,86 ****
#ifdef USE_SSL
! #define ROOT_CERT_FILE "root.crt"
! #define ROOT_CRL_FILE "root.crl"
! #define SERVER_CERT_FILE "server.crt"
! #define SERVER_PRIVATE_KEY_FILE "server.key"
static DH *load_dh_file(int keylength);
static DH *load_dh_buffer(const char *, size_t);
--- 77,86 ----
#ifdef USE_SSL
! char *ssl_cert_file;
! char *ssl_key_file;
! char *ssl_ca_file;
! char *ssl_crl_file;
static DH *load_dh_file(int keylength);
static DH *load_dh_buffer(const char *, size_t);
***************
*** 746,762 **** initialize_SSL(void)
* Load and verify server's certificate and private key
*/
if (SSL_CTX_use_certificate_chain_file(SSL_context,
! SERVER_CERT_FILE) != 1)
ereport(FATAL,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not load server certificate file \"%s\": %s",
! SERVER_CERT_FILE, SSLerrmessage())));
! if (stat(SERVER_PRIVATE_KEY_FILE, &buf) != 0)
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not access private key file \"%s\": %m",
! SERVER_PRIVATE_KEY_FILE)));
/*
* Require no public access to key file.
--- 746,762 ----
* Load and verify server's certificate and private key
*/
if (SSL_CTX_use_certificate_chain_file(SSL_context,
! ssl_cert_file) != 1)
ereport(FATAL,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not load server certificate file \"%s\": %s",
! ssl_cert_file, SSLerrmessage())));
! if (stat(ssl_key_file, &buf) != 0)
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not access private key file \"%s\": %m",
! ssl_key_file)));
/*
* Require no public access to key file.
***************
*** 771,786 **** initialize_SSL(void)
ereport(FATAL,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("private key file \"%s\" has group or world access",
! SERVER_PRIVATE_KEY_FILE),
errdetail("Permissions should be u=rw (0600) or less.")));
#endif
if (SSL_CTX_use_PrivateKey_file(SSL_context,
! SERVER_PRIVATE_KEY_FILE,
SSL_FILETYPE_PEM) != 1)
ereport(FATAL,
(errmsg("could not load private key file \"%s\": %s",
! SERVER_PRIVATE_KEY_FILE, SSLerrmessage())));
if (SSL_CTX_check_private_key(SSL_context) != 1)
ereport(FATAL,
--- 771,786 ----
ereport(FATAL,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("private key file \"%s\" has group or world access",
! ssl_key_file),
errdetail("Permissions should be u=rw (0600) or less.")));
#endif
if (SSL_CTX_use_PrivateKey_file(SSL_context,
! ssl_key_file,
SSL_FILETYPE_PEM) != 1)
ereport(FATAL,
(errmsg("could not load private key file \"%s\": %s",
! ssl_key_file, SSLerrmessage())));
if (SSL_CTX_check_private_key(SSL_context) != 1)
ereport(FATAL,
***************
*** 797,844 **** initialize_SSL(void)
elog(FATAL, "could not set the cipher list (no valid ciphers available)");
/*
! * Attempt to load CA store, so we can verify client certificates if
! * needed.
*/
! ssl_loaded_verify_locations = false;
!
! if (access(ROOT_CERT_FILE, R_OK) != 0)
{
! /*
! * If root certificate file simply not found, don't log an error here,
! * because it's quite likely the user isn't planning on using client
! * certificates. If we can't access it for other reasons, it is an
! * error.
! */
! if (errno != ENOENT)
ereport(FATAL,
! (errmsg("could not access root certificate file \"%s\": %m",
! ROOT_CERT_FILE)));
}
! else if (SSL_CTX_load_verify_locations(SSL_context, ROOT_CERT_FILE, NULL) != 1 ||
! (root_cert_list = SSL_load_client_CA_file(ROOT_CERT_FILE)) == NULL)
! {
! /*
! * File was there, but we could not load it. This means the file is
! * somehow broken, and we cannot do verification at all - so fail.
! */
! ereport(FATAL,
! (errmsg("could not load root certificate file \"%s\": %s",
! ROOT_CERT_FILE, SSLerrmessage())));
! }
! else
{
- /*----------
- * Load the Certificate Revocation List (CRL) if file exists.
- * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html
- *----------
- */
X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context);
if (cvstore)
{
/* Set the flags to check against the complete CRL chain */
! if (X509_STORE_load_locations(cvstore, ROOT_CRL_FILE, NULL) == 1)
{
/* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
#ifdef X509_V_FLAG_CRL_CHECK
--- 797,826 ----
elog(FATAL, "could not set the cipher list (no valid ciphers available)");
/*
! * Load CA store, so we can verify client certificates if needed.
*/
! if (ssl_ca_file[0])
{
! if (SSL_CTX_load_verify_locations(SSL_context, ssl_ca_file, NULL) != 1 ||
! (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL)
ereport(FATAL,
! (errmsg("could not load root certificate file \"%s\": %s",
! ssl_ca_file, SSLerrmessage())));
}
!
! /*----------
! * Load the Certificate Revocation List (CRL).
! * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html
! *----------
! */
! if (ssl_crl_file[0])
{
X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context);
if (cvstore)
{
/* Set the flags to check against the complete CRL chain */
! if (X509_STORE_load_locations(cvstore, ssl_crl_file, NULL) == 1)
{
/* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
#ifdef X509_V_FLAG_CRL_CHECK
***************
*** 847,878 **** initialize_SSL(void)
#else
ereport(LOG,
(errmsg("SSL certificate revocation list file \"%s\" ignored",
! ROOT_CRL_FILE),
errdetail("SSL library does not support certificate revocation lists.")));
#endif
}
else
! {
! /* Not fatal - we do not require CRL */
! ereport(LOG,
! (errmsg("SSL certificate revocation list file \"%s\" not found, skipping: %s",
! ROOT_CRL_FILE, SSLerrmessage()),
! errdetail("Certificates will not be checked against revocation list.")));
! }
! /*
! * Always ask for SSL client cert, but don't fail if it's not
! * presented. We might fail such connections later, depending on
! * what we find in pg_hba.conf.
! */
! SSL_CTX_set_verify(SSL_context,
! (SSL_VERIFY_PEER |
! SSL_VERIFY_CLIENT_ONCE),
! verify_cb);
! /* Set flag to remember CA store is successfully loaded */
! ssl_loaded_verify_locations = true;
! }
/*
* Tell OpenSSL to send the list of root certs we trust to clients in
--- 829,859 ----
#else
ereport(LOG,
(errmsg("SSL certificate revocation list file \"%s\" ignored",
! ssl_crl_file),
errdetail("SSL library does not support certificate revocation lists.")));
#endif
}
else
! ereport(FATAL,
! (errmsg("could not load SSL certificate revocation list file \"%s\": %s",
! ssl_crl_file, SSLerrmessage())));
! }
! }
! if (ssl_ca_file[0])
! {
! /*
! * Always ask for SSL client cert, but don't fail if it's not
! * presented. We might fail such connections later, depending on
! * what we find in pg_hba.conf.
! */
! SSL_CTX_set_verify(SSL_context,
! (SSL_VERIFY_PEER |
! SSL_VERIFY_CLIENT_ONCE),
! verify_cb);
! /* Set flag to remember CA store is successfully loaded */
! ssl_loaded_verify_locations = true;
/*
* Tell OpenSSL to send the list of root certs we trust to clients in
*** i/src/backend/utils/misc/guc.c
--- w/src/backend/utils/misc/guc.c
***************
*** 39,44 ****
--- 39,45 ----
#include "funcapi.h"
#include "libpq/auth.h"
#include "libpq/be-fsstubs.h"
+ #include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "optimizer/cost.h"
***************
*** 2961,2966 **** static struct config_string ConfigureNamesString[] =
--- 2962,3007 ----
},
{
+ {"ssl_cert_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ gettext_noop("Location of the SSL server certificate file."),
+ NULL
+ },
+ &ssl_cert_file,
+ "server.crt",
+ NULL, NULL, NULL
+ },
+
+ {
+ {"ssl_key_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ gettext_noop("Location of the SSL server private key file."),
+ NULL
+ },
+ &ssl_key_file,
+ "server.key",
+ NULL, NULL, NULL
+ },
+
+ {
+ {"ssl_ca_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ gettext_noop("Location of the SSL certificate authority file."),
+ NULL
+ },
+ &ssl_ca_file,
+ "",
+ NULL, NULL, NULL
+ },
+
+ {
+ {"ssl_crl_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ gettext_noop("Location of the SSL certificate revocation list file."),
+ NULL
+ },
+ &ssl_crl_file,
+ "",
+ NULL, NULL, NULL
+ },
+
+ {
{"stats_temp_directory", PGC_SIGHUP, STATS_COLLECTOR,
gettext_noop("Writes temporary statistics files to the specified directory."),
NULL,
*** i/src/backend/utils/misc/postgresql.conf.sample
--- w/src/backend/utils/misc/postgresql.conf.sample
***************
*** 81,86 ****
--- 81,90 ----
#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers
# (change requires restart)
#ssl_renegotiation_limit = 512MB # amount of data between renegotiations
+ #ssl_cert_file = 'server.crt' # (change requires restart)
+ #ssl_key_file = 'server.key' # (change requires restart)
+ #ssl_ca_file = '' # (change requires restart)
+ #ssl_crl_file = '' # (change requires restart)
#password_encryption = on
#db_user_namespace = off
*** i/src/include/libpq/libpq.h
--- w/src/include/libpq/libpq.h
***************
*** 70,75 **** extern void pq_endcopyout(bool errorAbort);
--- 70,80 ----
/*
* prototypes for functions in be-secure.c
*/
+ extern char *ssl_cert_file;
+ extern char *ssl_key_file;
+ extern char *ssl_ca_file;
+ extern char *ssl_crl_file;
+
extern int secure_initialize(void);
extern bool secure_loaded_verify_locations(void);
extern void secure_destroy(void);
On ons, 2012-02-08 at 09:16 +0100, Magnus Hagander wrote:
I'm still worried about this. If we ignore a missing root.crt, then the
effect is that authentication and certificate verification might fail,
which would be annoying, but you'd notice it soon enough. But if we
ignore a missing root.crl, we are creating a security hole.Yes, ignoring a missing file in a security context is definitely not good.
It should throw an error.We have a few bad defaults from the old days around SSL for this, but if it
requires breaking backwards compatibility to get it right, I think we
should still do it.
Btw., should we also consider making similar changes on the libpq side?
Peter Eisentraut <peter_e@gmx.net> writes:
On ons, 2012-02-08 at 09:16 +0100, Magnus Hagander wrote:
Yes, ignoring a missing file in a security context is definitely not good.
It should throw an error.We have a few bad defaults from the old days around SSL for this, but if it
requires breaking backwards compatibility to get it right, I think we
should still do it.
Btw., should we also consider making similar changes on the libpq side?
I think that breaking compatibility of libpq's behavior is a whole lot
harder sell than changing things in a way that only affects what people
have to put into postgresql.conf. We've always treated the latter as
something that can change across major versions.
In particular, I observe that we get pushback anytime we break something
in a way that makes SSL config files be required on the client side;
see bug #6302 for most recent example.
regards, tom lane
On ons, 2012-02-29 at 14:20 -0500, Tom Lane wrote:
In particular, I observe that we get pushback anytime we break something
in a way that makes SSL config files be required on the client side;
see bug #6302 for most recent example.
*If* we were to make a change in libpq analogous to the server side, the
effect would be to make the files less required, which could actually
help the case of bug #6302.
Peter Eisentraut <peter_e@gmx.net> writes:
On ons, 2012-02-29 at 14:20 -0500, Tom Lane wrote:
In particular, I observe that we get pushback anytime we break something
in a way that makes SSL config files be required on the client side;
see bug #6302 for most recent example.
*If* we were to make a change in libpq analogous to the server side, the
effect would be to make the files less required, which could actually
help the case of bug #6302.
Hm? Obviously I misunderstood what changes you were proposing to make,
so would you mind spelling it out?
regards, tom lane
On ons, 2012-02-29 at 14:27 -0500, Tom Lane wrote:
Peter Eisentraut <peter_e@gmx.net> writes:
On ons, 2012-02-29 at 14:20 -0500, Tom Lane wrote:
In particular, I observe that we get pushback anytime we break something
in a way that makes SSL config files be required on the client side;
see bug #6302 for most recent example.*If* we were to make a change in libpq analogous to the server side, the
effect would be to make the files less required, which could actually
help the case of bug #6302.Hm? Obviously I misunderstood what changes you were proposing to make,
so would you mind spelling it out?
The details are to be determined, but a possible change would likely be
that instead of looking for a file and using it if and only if found,
there would be some kind of connection parameter saying "use this file
for this functionality", and otherwise it's not used. The particular
example would be the CRL file.
Peter Eisentraut <peter_e@gmx.net> writes:
On ons, 2012-02-29 at 14:27 -0500, Tom Lane wrote:
Hm? Obviously I misunderstood what changes you were proposing to make,
so would you mind spelling it out?
The details are to be determined, but a possible change would likely be
that instead of looking for a file and using it if and only if found,
there would be some kind of connection parameter saying "use this file
for this functionality", and otherwise it's not used. The particular
example would be the CRL file.
Mph. That seems unlikely to be a net win to me. The scenario I'm
imagining is that you ("you" being DBA for some group of people) didn't
have a CRL file before, and now you need one. Your administration
problem is to get that CRL file into place for all your users.
If we change as above, then you still have that admin problem, plus now
you have another: getting all your users to use the new connection
parameter. Which, as a rule, is going to be tough (for example, psql
has no easy way to make that happen). The new admin problem offers you
no leverage at all on the old one, either, since a user who's not
acquired the CRL file more than likely hasn't changed his connection
habits either.
There may or may not be some value in a connection parameter that allows
specifying a location besides ~/.postgresql/ for the SSL support files.
But I don't find any attraction in changing the default behavior.
regards, tom lane