<para>
To make use of this option the server must be built with
<acronym>SSL</acronym> support. Furthermore,
- <acronym>SSL</acronym> must be enabled at server start time
+ <acronym>SSL</acronym> must be enabled
by setting the <xref linkend="guc-ssl"> configuration parameter (see
<xref linkend="ssl-tcp"> for more information).
+ Otherwise, the <literal>hostssl</literal> record is ignored except for
+ logging a warning that it cannot match any connections.
</para>
</listitem>
</varlistentry>
<listitem>
<para>
Enables <acronym>SSL</> connections. Please read
- <xref linkend="ssl-tcp"> before using this. The default
- is <literal>off</>. This parameter can only be set at server
- start. <acronym>SSL</> communication is only possible with
- TCP/IP connections.
+ <xref linkend="ssl-tcp"> before using this.
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line.
+ The default is <literal>off</>.
</para>
</listitem>
</varlistentry>
<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.
+ authority (CA).
+ Relative paths are relative to the data directory.
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line.
+ The default is empty, meaning no CA file is loaded,
+ and client certificate verification is not performed.
+ </para>
+ <para>
+ In previous releases of PostgreSQL, the name of this file was
+ hard-coded as <filename>root.crt</filename>.
</para>
</listitem>
</varlistentry>
<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.
+ Relative paths are relative to the data directory.
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line.
+ The default is <filename>server.crt</filename>.
</para>
</listitem>
</varlistentry>
<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.
+ revocation list (CRL).
+ Relative paths are relative to the data directory.
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line.
+ The default is empty, meaning no CRL file is loaded.
+ </para>
+ <para>
+ In previous releases of PostgreSQL, the name of this file was
+ hard-coded as <filename>root.crl</filename>.
</para>
</listitem>
</varlistentry>
<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.
+ Relative paths are relative to the data directory.
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line.
+ The default is <filename>server.key</filename>.
</para>
</listitem>
</varlistentry>
used on secure connections. See
the <citerefentry><refentrytitle>ciphers</></citerefentry> manual page
in the <application>OpenSSL</> package for the syntax of this setting
- and a list of supported values. The default value is
- <literal>HIGH:MEDIUM:+3DES:!aNULL</>. It is usually reasonable,
- unless you have specific security requirements. This parameter can only
- be set at server start.
+ and a list of supported values.
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line.
+ The default value is <literal>HIGH:MEDIUM:+3DES:!aNULL</>. The
+ default is usually a reasonable choice unless you have specific
+ security requirements.
</para>
<para>
</varlistentry>
<varlistentry id="guc-ssl-prefer-server-ciphers" xreflabel="ssl_prefer_server_ciphers">
- <term><varname>ssl_prefer_server_ciphers</varname> (<type>bool</type>)
+ <term><varname>ssl_prefer_server_ciphers</varname> (<type>boolean</type>)
<indexterm>
<primary><varname>ssl_prefer_server_ciphers</> configuration parameter</primary>
</indexterm>
<listitem>
<para>
Specifies whether to use the server's SSL cipher preferences, rather
- than the client's. The default is true. This parameter can only be
- set at server start.
+ than the client's.
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line.
+ The default is <literal>true</>.
</para>
<para>
<para>
Specifies the name of the curve to use in <acronym>ECDH</> key
exchange. It needs to be supported by all clients that connect.
- It does not need to be same curve as used by server's Elliptic
- Curve key. The default is <literal>prime256v1</>. This parameter
- can only be set at server start.
+ It does not need to be the same curve used by the server's Elliptic
+ Curve key.
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line.
+ The default is <literal>prime256v1</>.
</para>
<para>
- OpenSSL names for most common curves:
+ OpenSSL names for the most common curves are:
<literal>prime256v1</> (NIST P-256),
<literal>secp384r1</> (NIST P-384),
<literal>secp521r1</> (NIST P-521).
- </para>
-
- <para>
The full list of available curves can be shown with the command
<command>openssl ecparam -list_curves</command>. Not all of them
are usable in <acronym>TLS</> though.
</varlistentry>
<varlistentry id="guc-track-commit-timestamp" xreflabel="track_commit_timestamp">
- <term><varname>track_commit_timestamp</varname> (<type>bool</type>)
+ <term><varname>track_commit_timestamp</varname> (<type>boolean</type>)
<indexterm>
<primary><varname>track_commit_timestamp</> configuration parameter</primary>
</indexterm>
</table>
<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.
+ The server reads these files at server start and whenever the server
+ configuration is reloaded. On <systemitem class="osname">Windows</>
+ systems, they are also re-read whenever a new backend process is spawned
+ for a new client connection.
+ </para>
+
+ <para>
+ If an error in these files is detected at server start, the server will
+ refuse to start. But if an error is detected during a configuration
+ reload, the files are ignored and the old values continue to be used.
+ On <systemitem class="osname">Windows</> systems, if an error in these
+ files is detected at backend start, that backend will be unable to
+ establish an SSL connection. In all these cases, the error condition is
+ reported in the server log.
</para>
</sect2>
*/
if (port->hba->clientcert)
{
+ /* If we haven't loaded a root certificate store, fail */
+ if (!secure_loaded_verify_locations())
+ ereport(FATAL,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("client certificates can only be checked if a root certificate store is available")));
+
/*
- * When we parse pg_hba.conf, we have already made sure that we have
- * been able to load a certificate store. Thus, if a certificate is
- * present on the client, it has been verified against our root
+ * If we loaded a root certificate store, and if a certificate is
+ * present on the client, then it has been verified against our root
* certificate store, and the connection would have been aborted
* already if it didn't verify ok.
*/
-#ifdef USE_SSL
if (!port->peer_cert_valid)
- {
ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("connection requires a valid client certificate")));
- }
-#else
-
- /*
- * hba.c makes sure hba->clientcert can't be set unless OpenSSL is
- * present.
- */
- Assert(false);
-#endif
}
/*
static DH *tmp_dh_cb(SSL *s, int is_export, int keylength);
static int verify_cb(int, X509_STORE_CTX *);
static void info_cb(const SSL *ssl, int type, int args);
-static void initialize_ecdh(void);
+static bool initialize_ecdh(SSL_CTX *context, bool failOnError);
static const char *SSLerrmessage(unsigned long ecode);
static char *X509_NAME_to_cstring(X509_NAME *name);
static SSL_CTX *SSL_context = NULL;
+static bool SSL_initialized = false;
/* ------------------------------------------------------------ */
/* Hardcoded values */
/*
* Initialize global SSL context.
+ *
+ * If failOnError is true, report any errors as FATAL (so we don't return).
+ * Otherwise, log errors at LOG level and return -1 to indicate trouble.
+ * Returns 0 if OK.
*/
-void
-be_tls_init(void)
+int
+be_tls_init(bool failOnError)
{
- struct stat buf;
-
STACK_OF(X509_NAME) *root_cert_list = NULL;
+ SSL_CTX *context;
+ struct stat buf;
- if (!SSL_context)
+ /* This stuff need be done only once. */
+ if (!SSL_initialized)
{
#ifdef HAVE_OPENSSL_INIT_SSL
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
SSL_library_init();
SSL_load_error_strings();
#endif
+ SSL_initialized = true;
+ }
- /*
- * We use SSLv23_method() because it can negotiate use of the highest
- * mutually supported protocol version, while alternatives like
- * TLSv1_2_method() permit only one specific version. Note that we
- * don't actually allow SSL v2 or v3, only TLS protocols (see below).
- */
- SSL_context = SSL_CTX_new(SSLv23_method());
- if (!SSL_context)
- ereport(FATAL,
- (errmsg("could not create SSL context: %s",
- SSLerrmessage(ERR_get_error()))));
+ /*
+ * We use SSLv23_method() because it can negotiate use of the highest
+ * mutually supported protocol version, while alternatives like
+ * TLSv1_2_method() permit only one specific version. Note that we don't
+ * actually allow SSL v2 or v3, only TLS protocols (see below).
+ */
+ context = SSL_CTX_new(SSLv23_method());
+ if (!context)
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errmsg("could not create SSL context: %s",
+ SSLerrmessage(ERR_get_error()))));
+ goto error;
+ }
- /*
- * Disable OpenSSL's moving-write-buffer sanity check, because it
- * causes unnecessary failures in nonblocking send cases.
- */
- SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ /*
+ * Disable OpenSSL's moving-write-buffer sanity check, because it causes
+ * unnecessary failures in nonblocking send cases.
+ */
+ SSL_CTX_set_mode(context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
- /*
- * 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(ERR_get_error()))));
+ /*
+ * Load and verify server's certificate and private key
+ */
+ if (SSL_CTX_use_certificate_chain_file(context, ssl_cert_file) != 1)
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("could not load server certificate file \"%s\": %s",
+ ssl_cert_file, SSLerrmessage(ERR_get_error()))));
+ goto error;
+ }
- 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)));
+ if (stat(ssl_key_file, &buf) != 0)
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode_for_file_access(),
+ errmsg("could not access private key file \"%s\": %m",
+ ssl_key_file)));
+ goto error;
+ }
- if (!S_ISREG(buf.st_mode))
- ereport(FATAL,
- (errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("private key file \"%s\" is not a regular file",
- ssl_key_file)));
+ if (!S_ISREG(buf.st_mode))
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("private key file \"%s\" is not a regular file",
+ ssl_key_file)));
+ goto error;
+ }
- /*
- * Refuse to load files owned by users other than us or root.
- *
- * XXX surely we can check this on Windows somehow, too.
- */
+ /*
+ * Refuse to load files owned by users other than us or root.
+ *
+ * XXX surely we can check this on Windows somehow, too.
+ */
#if !defined(WIN32) && !defined(__CYGWIN__)
- if (buf.st_uid != geteuid() && buf.st_uid != 0)
- ereport(FATAL,
- (errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("private key file \"%s\" must be owned by the database user or root",
- ssl_key_file)));
+ if (buf.st_uid != geteuid() && buf.st_uid != 0)
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("private key file \"%s\" must be owned by the database user or root",
+ ssl_key_file)));
+ goto error;
+ }
#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)
- */
+ /*
+ * 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)))
- ereport(FATAL,
- (errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("private key file \"%s\" has group or world access",
- ssl_key_file),
- errdetail("File must have permissions u=rw (0600) or less if owned by the database user, or permissions u=rw,g=r (0640) or less if owned by root.")));
+ 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)))
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("private key file \"%s\" has group or world access",
+ ssl_key_file),
+ errdetail("File must have permissions u=rw (0600) or less if owned by the database user, or permissions u=rw,g=r (0640) or less if owned by root.")));
+ goto error;
+ }
#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(ERR_get_error()))));
-
- if (SSL_CTX_check_private_key(SSL_context) != 1)
- ereport(FATAL,
- (errmsg("check of private key failed: %s",
- SSLerrmessage(ERR_get_error()))));
+ if (SSL_CTX_use_PrivateKey_file(context,
+ ssl_key_file,
+ SSL_FILETYPE_PEM) != 1)
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("could not load private key file \"%s\": %s",
+ ssl_key_file, SSLerrmessage(ERR_get_error()))));
+ goto error;
+ }
+
+ if (SSL_CTX_check_private_key(context) != 1)
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("check of private key failed: %s",
+ SSLerrmessage(ERR_get_error()))));
+ goto error;
}
/* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */
- SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb);
- SSL_CTX_set_options(SSL_context,
+ SSL_CTX_set_tmp_dh_callback(context, tmp_dh_cb);
+ SSL_CTX_set_options(context,
SSL_OP_SINGLE_DH_USE |
SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
/* set up ephemeral ECDH keys */
- initialize_ecdh();
+ if (!initialize_ecdh(context, failOnError))
+ goto error;
/* set up the allowed cipher list */
- if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1)
- elog(FATAL, "could not set the cipher list (no valid ciphers available)");
+ if (SSL_CTX_set_cipher_list(context, SSLCipherSuites) != 1)
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("could not set the cipher list (no valid ciphers available)")));
+ goto error;
+ }
/* Let server choose order */
if (SSLPreferServerCiphers)
- SSL_CTX_set_options(SSL_context, SSL_OP_CIPHER_SERVER_PREFERENCE);
+ SSL_CTX_set_options(context, SSL_OP_CIPHER_SERVER_PREFERENCE);
/*
* 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 ||
+ if (SSL_CTX_load_verify_locations(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",
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("could not load root certificate file \"%s\": %s",
ssl_ca_file, SSLerrmessage(ERR_get_error()))));
+ goto error;
+ }
}
/*----------
*/
if (ssl_crl_file[0])
{
- X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context);
+ X509_STORE *cvstore = SSL_CTX_get_cert_store(context);
if (cvstore)
{
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
#else
ereport(LOG,
- (errmsg("SSL certificate revocation list file \"%s\" ignored",
- ssl_crl_file),
- errdetail("SSL library does not support certificate revocation lists.")));
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ 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",
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("could not load SSL certificate revocation list file \"%s\": %s",
ssl_crl_file, SSLerrmessage(ERR_get_error()))));
+ goto error;
+ }
}
}
* presented. We might fail such connections later, depending on what
* we find in pg_hba.conf.
*/
- SSL_CTX_set_verify(SSL_context,
+ SSL_CTX_set_verify(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
* CertificateRequests. This lets a client with a keystore select the
* appropriate client certificate to send to us.
*/
- SSL_CTX_set_client_CA_list(SSL_context, root_cert_list);
+ SSL_CTX_set_client_CA_list(context, root_cert_list);
}
+
+ /*
+ * Success! Replace any existing SSL_context.
+ */
+ if (SSL_context)
+ SSL_CTX_free(SSL_context);
+
+ SSL_context = context;
+
+ /*
+ * Set flag to remember whether CA store has been loaded into SSL_context.
+ */
+ if (ssl_ca_file[0])
+ ssl_loaded_verify_locations = true;
+ else
+ ssl_loaded_verify_locations = false;
+
+ return 0;
+
+error:
+ if (context)
+ SSL_CTX_free(context);
+ return -1;
+}
+
+/*
+ * Destroy global SSL context, if any.
+ */
+void
+be_tls_destroy(void)
+{
+ if (SSL_context)
+ SSL_CTX_free(SSL_context);
+ SSL_context = NULL;
+ ssl_loaded_verify_locations = false;
}
/*
Assert(!port->ssl);
Assert(!port->peer);
+ if (!SSL_context)
+ {
+ ereport(COMMERROR,
+ (errcode(ERRCODE_PROTOCOL_VIOLATION),
+ errmsg("could not initialize SSL connection: SSL context not set up")));
+ return -1;
+ }
+
if (!(port->ssl = SSL_new(SSL_context)))
{
ereport(COMMERROR,
!BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) ||
!BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) ||
!BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) ||
- !BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) ||
+ !BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) ||
!BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom)))
{
BIO_meth_free(my_bio_methods);
}
}
-static void
-initialize_ecdh(void)
+static bool
+initialize_ecdh(SSL_CTX *context, bool failOnError)
{
#ifndef OPENSSL_NO_ECDH
EC_KEY *ecdh;
nid = OBJ_sn2nid(SSLECDHCurve);
if (!nid)
- ereport(FATAL,
- (errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve)));
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve)));
+ return false;
+ }
ecdh = EC_KEY_new_by_curve_name(nid);
if (!ecdh)
- ereport(FATAL,
- (errmsg("ECDH: could not create key")));
+ {
+ ereport(failOnError ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("ECDH: could not create key")));
+ return false;
+ }
- SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_ECDH_USE);
- SSL_CTX_set_tmp_ecdh(SSL_context, ecdh);
+ SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
+ SSL_CTX_set_tmp_ecdh(context, ecdh);
EC_KEY_free(ecdh);
#endif
+
+ return true;
}
/*
/* ------------------------------------------------------------ */
/*
- * Initialize global context
+ * Initialize global context.
+ *
+ * If failOnError is true, report any errors as FATAL (so we don't return).
+ * Otherwise, log errors at LOG level and return -1 to indicate trouble.
+ * Returns 0 if OK.
*/
int
-secure_initialize(void)
+secure_initialize(bool failOnError)
{
#ifdef USE_SSL
- be_tls_init();
+ return be_tls_init(failOnError);
+#else
+ return 0;
#endif
+}
- return 0;
+/*
+ * Destroy global context, if any.
+ */
+void
+secure_destroy(void)
+{
+#ifdef USE_SSL
+ be_tls_destroy();
+#endif
}
/*
if (token->string[4] == 's') /* "hostssl" */
{
- /* SSL support must be actually active, else complain */
+ parsedline->conntype = ctHostSSL;
+ /* Log a warning if SSL support is not active */
#ifdef USE_SSL
- if (EnableSSL)
- parsedline->conntype = ctHostSSL;
- else
- {
+ if (!EnableSSL)
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("hostssl requires SSL to be turned on"),
+ errmsg("hostssl record cannot match because SSL is disabled"),
errhint("Set ssl = on in postgresql.conf."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
- return NULL;
- }
#else
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("hostssl is not supported by this build"),
+ errmsg("hostssl record cannot match because SSL is not supported by this build"),
errhint("Compile with --with-openssl to use SSL connections."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
- return NULL;
#endif
}
else if (token->string[4] == 'n') /* "hostnossl" */
}
else if (strcmp(name, "clientcert") == 0)
{
- /*
- * Since we require ctHostSSL, this really can never happen on
- * non-SSL-enabled builds, so don't bother checking for USE_SSL.
- */
if (hbaline->conntype != ctHostSSL)
{
ereport(LOG,
}
if (strcmp(val, "1") == 0)
{
- if (!secure_loaded_verify_locations())
- {
- ereport(LOG,
- (errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("client certificates can only be checked if a root certificate store is available"),
- errhint("Make sure the configuration parameter \"%s\" is set.", "ssl_ca_file"),
- errcontext("line %d of configuration file \"%s\"",
- line_num, HbaFileName)));
- return false;
- }
hbaline->clientcert = true;
}
else
static struct timeval random_start_time;
#endif
+#ifdef USE_SSL
+/* Set when and if SSL has been initialized properly */
+static bool LoadedSSL = false;
+#endif
+
#ifdef USE_BONJOUR
static DNSServiceRef bonjour_sdref = NULL;
#endif
*/
#ifdef USE_SSL
if (EnableSSL)
- secure_initialize();
+ {
+ (void) secure_initialize(true);
+ LoadedSSL = true;
+ }
#endif
/*
#ifdef USE_SSL
/* No SSL when disabled or on Unix sockets */
- if (!EnableSSL || IS_AF_UNIX(port->laddr.addr.ss_family))
+ if (!LoadedSSL || IS_AF_UNIX(port->laddr.addr.ss_family))
SSLok = 'N';
else
SSLok = 'S'; /* Support for SSL */
/* Reload authentication config files too */
if (!load_hba())
- ereport(WARNING,
+ ereport(LOG,
(errmsg("pg_hba.conf not reloaded")));
if (!load_ident())
- ereport(WARNING,
+ ereport(LOG,
(errmsg("pg_ident.conf not reloaded")));
+#ifdef USE_SSL
+ /* Reload SSL configuration as well */
+ if (EnableSSL)
+ {
+ if (secure_initialize(false) == 0)
+ LoadedSSL = true;
+ else
+ ereport(LOG,
+ (errmsg("SSL context not reloaded")));
+ }
+ else
+ {
+ secure_destroy();
+ LoadedSSL = false;
+ }
+#endif
+
#ifdef EXEC_BACKEND
/* Update the starting-point file for future children */
write_nondefault_variables(PGC_SIGHUP);
* context structures contain function pointers and cannot be passed
* through the parameter file.
*
+ * If for some reason reload fails (maybe the user installed broken
+ * key files), soldier on without SSL; that's better than all
+ * connections becoming impossible.
+ *
* XXX should we do this in all child processes? For the moment it's
* enough to do it in backend children.
*/
#ifdef USE_SSL
if (EnableSSL)
- secure_initialize();
+ {
+ if (secure_initialize(false) == 0)
+ LoadedSSL = true;
+ else
+ ereport(LOG,
+ (errmsg("SSL context could not be reloaded in child process")));
+ }
#endif
/*
NULL, NULL, NULL
},
{
- {"ssl", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ {"ssl", PGC_SIGHUP, CONN_AUTH_SECURITY,
gettext_noop("Enables SSL connections."),
NULL
},
check_ssl, NULL, NULL
},
{
- {"ssl_prefer_server_ciphers", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ {"ssl_prefer_server_ciphers", PGC_SIGHUP, CONN_AUTH_SECURITY,
gettext_noop("Give priority to server ciphersuite order."),
NULL
},
GUC_UNIT_XBLOCKS
},
&WalWriterFlushAfter,
- (1024*1024) / XLOG_BLCKSZ, 0, INT_MAX,
+ (1024 * 1024) / XLOG_BLCKSZ, 0, INT_MAX,
NULL, NULL, NULL
},
},
{
- {"ssl_cert_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ {"ssl_cert_file", PGC_SIGHUP, CONN_AUTH_SECURITY,
gettext_noop("Location of the SSL server certificate file."),
NULL
},
},
{
- {"ssl_key_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ {"ssl_key_file", PGC_SIGHUP, CONN_AUTH_SECURITY,
gettext_noop("Location of the SSL server private key file."),
NULL
},
},
{
- {"ssl_ca_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ {"ssl_ca_file", PGC_SIGHUP, CONN_AUTH_SECURITY,
gettext_noop("Location of the SSL certificate authority file."),
NULL
},
},
{
- {"ssl_crl_file", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ {"ssl_crl_file", PGC_SIGHUP, CONN_AUTH_SECURITY,
gettext_noop("Location of the SSL certificate revocation list file."),
NULL
},
},
{
- {"ssl_ciphers", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ {"ssl_ciphers", PGC_SIGHUP, CONN_AUTH_SECURITY,
gettext_noop("Sets the list of allowed SSL ciphers."),
NULL,
GUC_SUPERUSER_ONLY
},
{
- {"ssl_ecdh_curve", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+ {"ssl_ecdh_curve", PGC_SIGHUP, CONN_AUTH_SECURITY,
gettext_noop("Sets the curve to use for ECDH."),
NULL,
GUC_SUPERUSER_ONLY
# - Security and Authentication -
#authentication_timeout = 1min # 1s-600s
-#ssl = off # (change requires restart)
+#ssl = off
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
- # (change requires restart)
-#ssl_prefer_server_ciphers = on # (change requires restart)
-#ssl_ecdh_curve = 'prime256v1' # (change requires restart)
-#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)
+#ssl_prefer_server_ciphers = on
+#ssl_ecdh_curve = 'prime256v1'
+#ssl_cert_file = 'server.crt'
+#ssl_key_file = 'server.key'
+#ssl_ca_file = ''
+#ssl_crl_file = ''
#password_encryption = md5 # md5 or plain
#db_user_namespace = off
#row_security = on
* These functions are implemented by the glue code specific to each
* SSL implementation (e.g. be-secure-openssl.c)
*/
-extern void be_tls_init(void);
+extern int be_tls_init(bool failOnError);
+extern void be_tls_destroy(void);
extern int be_tls_open_server(Port *port);
extern void be_tls_close(Port *port);
extern ssize_t be_tls_read(Port *port, void *ptr, size_t len, int *waitfor);
extern char *ssl_ca_file;
extern char *ssl_crl_file;
-extern int secure_initialize(void);
+extern int secure_initialize(bool failOnError);
extern bool secure_loaded_verify_locations(void);
extern void secure_destroy(void);
extern int secure_open_server(Port *port);
close CONF;
-# Copy all server certificates and keys, and client root cert, to the data dir
+ # ssl configuration will be placed here
+ open SSLCONF, ">$pgdata/sslconfig.conf";
+ close SSLCONF;
+
+ # Copy all server certificates and keys, and client root cert, to the data dir
copy_files("ssl/server-*.crt", $pgdata);
copy_files("ssl/server-*.key", $pgdata);
chmod(0600, glob "$pgdata/server-*.key") or die $!;
copy_files("ssl/root_ca.crt", $pgdata);
copy_files("ssl/root+client.crl", $pgdata);
- # Only accept SSL connections from localhost. Our tests don't depend on this
- # but seems best to keep it as narrow as possible for security reasons.
- #
- # When connecting to certdb, also check the client certificate.
- open HBA, ">$pgdata/pg_hba.conf";
- print HBA
-"# TYPE DATABASE USER ADDRESS METHOD\n";
- print HBA
-"hostssl trustdb ssltestuser $serverhost/32 trust\n";
- print HBA
-"hostssl trustdb ssltestuser ::1/128 trust\n";
- print HBA
-"hostssl certdb ssltestuser $serverhost/32 cert\n";
- print HBA
-"hostssl certdb ssltestuser ::1/128 cert\n";
- close HBA;
+ # Stop and restart server to load new listen_addresses.
+ $node->restart;
+
+ # Change pg_hba after restart because hostssl requires ssl=on
+ configure_hba_for_ssl($node, $serverhost);
}
-# Change the configuration to use given server cert file, and restart
+# Change the configuration to use given server cert file, and reload
# the server so that the configuration takes effect.
sub switch_server_cert
{
my $cafile = $_[2] || "root+client_ca";
my $pgdata = $node->data_dir;
- diag "Restarting server with certfile \"$certfile\" and cafile \"$cafile\"...";
+ diag "Reloading server with certfile \"$certfile\" and cafile \"$cafile\"...";
open SSLCONF, ">$pgdata/sslconfig.conf";
print SSLCONF "ssl=on\n";
print SSLCONF "ssl_crl_file='root+client.crl'\n";
close SSLCONF;
- # Stop and restart server to reload the new config.
- $node->restart;
+ $node->reload;
+}
+
+sub configure_hba_for_ssl
+{
+ my $node = $_[0];
+ my $serverhost = $_[1];
+ my $pgdata = $node->data_dir;
+
+ # Only accept SSL connections from localhost. Our tests don't depend on this
+ # but seems best to keep it as narrow as possible for security reasons.
+ #
+ # When connecting to certdb, also check the client certificate.
+ open HBA, ">$pgdata/pg_hba.conf";
+ print HBA
+"# TYPE DATABASE USER ADDRESS METHOD\n";
+ print HBA
+"hostssl trustdb ssltestuser $serverhost/32 trust\n";
+ print HBA
+"hostssl trustdb ssltestuser ::1/128 trust\n";
+ print HBA
+"hostssl certdb ssltestuser $serverhost/32 cert\n";
+ print HBA
+"hostssl certdb ssltestuser ::1/128 cert\n";
+ close HBA;
}