SSL improvements:
o read global SSL configuration file o add GUC "ssl_ciphers" to control allowed ciphers o add libpq environment variable PGSSLKEY to control SSL hardware keys Victor B. Wagner
This commit is contained in:
parent
68046a20c7
commit
c7b08050d9
@ -1,4 +1,4 @@
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.110 2007/02/08 15:46:03 momjian Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.111 2007/02/16 02:59:40 momjian Exp $ -->
|
||||
|
||||
<chapter Id="runtime-config">
|
||||
<title>Server Configuration</title>
|
||||
@ -569,6 +569,20 @@ SET ENABLE_SEQSCAN TO OFF;
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="guc-ssl-ciphers" xreflabel="ssl-ciphers">
|
||||
<term><varname>ssl_ciphers> (<type>string</type>)</term>
|
||||
<indexterm>
|
||||
<primary><varname>ssl_ciphers</> configuration parameter</primary>
|
||||
</indexterm>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies a list of <acronym>SSL</> ciphers which can be used to
|
||||
establish secure connections. See the <application>openssl</>
|
||||
manual page for a list of supported ciphers.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="guc-password-encryption" xreflabel="password_encryption">
|
||||
<term><varname>password_encryption</varname> (<type>boolean</type>)</term>
|
||||
<indexterm>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.228 2007/02/06 03:03:11 tgl Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.229 2007/02/16 02:59:40 momjian Exp $ -->
|
||||
|
||||
<chapter id="libpq">
|
||||
<title><application>libpq</application> - C Library</title>
|
||||
@ -4174,6 +4174,18 @@ setting, and is only available if
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<indexterm>
|
||||
<primary><envar>PGSSLKEY</envar></primary>
|
||||
</indexterm>
|
||||
<envar>PGSSLKEY</envar>
|
||||
specifies the hardware token which stores the secret key for the client
|
||||
certificate, instead of a file. The value of this variable should consist
|
||||
of a colon-separated engine name (engines are <productname>OpenSSL</>
|
||||
loadable modules) and an engine-specific key identifier.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<indexterm>
|
||||
<primary><envar>PGKRBSRVNAME</envar></primary>
|
||||
</indexterm>
|
||||
@ -4438,19 +4450,44 @@ ldap://ldap.mycompany.com/dc=mycompany,dc=com?uniqueMember?one?(cn=mydatabase)
|
||||
for increased security. See <xref linkend="ssl-tcp"> for details
|
||||
about the server-side <acronym>SSL</> functionality.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<application>libpq</application> reads the system-wide
|
||||
<productname>OpenSSL</productname> configuration file. By default, this
|
||||
file is named <filename>openssl.cnf</filename> and is located in the
|
||||
directory reported by <application>openssl</>:
|
||||
<programlisting>
|
||||
openssl version -d
|
||||
</programlisting>
|
||||
The default can be overriden by setting environment variable
|
||||
<envar>OPENSSL_CONF</envar> to the name of the desired configuration
|
||||
file.
|
||||
</para>
|
||||
<para>
|
||||
If the server demands a client certificate,
|
||||
<application>libpq</application>
|
||||
will send the certificate stored in file
|
||||
<filename>~/.postgresql/postgresql.crt</> within the user's home directory.
|
||||
A matching private key file <filename>~/.postgresql/postgresql.key</>
|
||||
must also be present, and must not be world-readable.
|
||||
must also be present, and must not be world-readable, unless the secret
|
||||
key is stored in a hardware token, as specified by
|
||||
<envar>PGSSLKEY</envar>.
|
||||
(On Microsoft Windows these files are named
|
||||
<filename>%APPDATA%\postgresql\postgresql.crt</filename> and
|
||||
<filename>%APPDATA%\postgresql\postgresql.key</filename>.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the environment variable <envar>PGSSLKEY</envar> is set, its value
|
||||
should consist of a colon-separated engine name and key identifier. In
|
||||
this case, <application>libpq</application> will load the specified
|
||||
engine, i.e. the <productname>OpenSSL</> module which supports special
|
||||
hardware and reference the key with the specified identifier.
|
||||
Identifiers are engine-specific. Typically, cryptography hardware tokens
|
||||
do not reveal secret keys to the application. Instead, applications
|
||||
delegate all cryptography operations which require the secret key to
|
||||
the hardware token.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the file <filename>~/.postgresql/root.crt</> is present in the user's
|
||||
home directory,
|
||||
|
@ -1,4 +1,4 @@
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.376 2007/02/01 00:28:18 momjian Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.377 2007/02/16 02:59:40 momjian Exp $ -->
|
||||
|
||||
<chapter Id="runtime">
|
||||
<title>Operating System Environment</title>
|
||||
@ -1515,6 +1515,25 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
|
||||
require use of <acronym>SSL</> for some or all connections.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<productname>OpenSSL</productname> supports a wide range of ciphers
|
||||
and authentication algorithms, whose strength varies significantly.
|
||||
You can restrict the list of ciphers which can be used to connect to
|
||||
your server using the <xref linkend="guc-ssl-ciphers"> parameter.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<productname>PostgreSQL</productname> reads a system-wide
|
||||
<productname>OpenSSL</productname> configuration file. By default this
|
||||
file is named <filename>openssl.cnf</filename> and is located in the
|
||||
directory reported by <application>openssl</>:
|
||||
<programlisting>
|
||||
openssl version -d
|
||||
</programlisting>
|
||||
This default can be overriden by setting environment variable
|
||||
<envar>OPENSSL_CONF</envar> to the name of desired configuration file.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For details on how to create your server private key and certificate,
|
||||
refer to the <productname>OpenSSL</> documentation. A
|
||||
@ -1528,8 +1547,8 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
|
||||
<programlisting>
|
||||
openssl req -new -text -out server.req
|
||||
</programlisting>
|
||||
Fill out the information that <command>openssl</> asks for. Make sure
|
||||
that you enter the local host name as <quote>Common Name</>; the challenge
|
||||
Fill out the information that <application>openssl</> asks for. Make sure
|
||||
you enter the local host name as <quote>Common Name</>; the challenge
|
||||
password can be left blank. The program will generate a key that is
|
||||
passphrase protected; it will not accept a passphrase that is less
|
||||
than four characters long. To remove the passphrase (as you must if
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.77 2007/02/07 00:52:35 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.78 2007/02/16 02:59:40 momjian Exp $
|
||||
*
|
||||
* Since the server static private key ($DataDir/server.key)
|
||||
* will normally be stored unencrypted so that the database
|
||||
@ -92,6 +92,10 @@
|
||||
#ifdef USE_SSL
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/dh.h>
|
||||
#if SSLEAY_VERSION_NUMBER >= 0x0907000L
|
||||
#include <openssl/conf.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "libpq/libpq.h"
|
||||
@ -125,6 +129,10 @@ static const char *SSLerrmessage(void);
|
||||
#define RENEGOTIATION_LIMIT (512 * 1024 * 1024)
|
||||
|
||||
static SSL_CTX *SSL_context = NULL;
|
||||
|
||||
/* GUC variable controlling SSL cipher list*/
|
||||
extern char *SSLCipherSuites;
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@ -719,6 +727,9 @@ initialize_SSL(void)
|
||||
|
||||
if (!SSL_context)
|
||||
{
|
||||
#if SSLEAY_VERSION_NUMBER >= 0x0907000L
|
||||
OPENSSL_config(NULL);
|
||||
#endif
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
SSL_context = SSL_CTX_new(SSLv23_method());
|
||||
@ -780,7 +791,7 @@ initialize_SSL(void)
|
||||
SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2);
|
||||
|
||||
/* setup the allowed cipher list */
|
||||
if (SSL_CTX_set_cipher_list(SSL_context, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") != 1)
|
||||
if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1)
|
||||
elog(FATAL, "could not set the cipher list (no valid ciphers available)");
|
||||
|
||||
/*
|
||||
|
@ -37,7 +37,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.523 2007/02/16 02:10:07 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.524 2007/02/16 02:59:41 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@ -187,6 +187,7 @@ static int SendStop = false;
|
||||
|
||||
/* still more option variables */
|
||||
bool EnableSSL = false;
|
||||
char *SSLCipherSuites;
|
||||
bool SilentMode = false; /* silent mode (-S) */
|
||||
|
||||
int PreAuthDelay = 0;
|
||||
|
@ -10,7 +10,7 @@
|
||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.374 2007/02/14 03:08:44 neilc Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.375 2007/02/16 02:59:41 momjian Exp $
|
||||
*
|
||||
*--------------------------------------------------------------------
|
||||
*/
|
||||
@ -2314,6 +2314,16 @@ static struct config_string ConfigureNamesString[] =
|
||||
NULL, assign_temp_tablespaces, NULL
|
||||
},
|
||||
|
||||
{
|
||||
{"ssl_ciphers", PGC_POSTMASTER, CONN_AUTH_SECURITY,
|
||||
gettext_noop("Sets the list of allowed SSL ciphers."),
|
||||
NULL,
|
||||
GUC_SUPERUSER_ONLY
|
||||
},
|
||||
&SSLCipherSuites,
|
||||
"ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH", NULL, NULL
|
||||
},
|
||||
|
||||
/* End-of-list marker */
|
||||
{
|
||||
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
|
||||
|
@ -74,6 +74,7 @@
|
||||
|
||||
#authentication_timeout = 1min # 1s-600s
|
||||
#ssl = off # (change requires restart)
|
||||
#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # List of ciphers to use
|
||||
#password_encryption = on
|
||||
#db_user_namespace = off
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/postmaster/postmaster.h,v 1.15 2007/01/05 22:19:57 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/postmaster/postmaster.h,v 1.16 2007/02/16 02:59:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
/* GUC options */
|
||||
extern bool EnableSSL;
|
||||
extern char *SSLCipherSuites;
|
||||
extern bool SilentMode;
|
||||
extern int ReservedBackends;
|
||||
extern int PostPortNumber;
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.92 2007/02/08 11:10:27 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.93 2007/02/16 02:59:41 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* [ Most of these notes are wrong/obsolete, but perhaps not all ]
|
||||
@ -111,6 +111,12 @@
|
||||
|
||||
#ifdef USE_SSL
|
||||
#include <openssl/ssl.h>
|
||||
#if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
|
||||
#include <openssl/conf.h>
|
||||
#endif
|
||||
#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
|
||||
#include <openssl/engine.h>
|
||||
#endif
|
||||
#endif /* USE_SSL */
|
||||
|
||||
|
||||
@ -606,54 +612,99 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
/* read the user key */
|
||||
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);
|
||||
if (stat(fnbuf, &buf) == -1)
|
||||
#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
|
||||
if (getenv("PGSSLKEY"))
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("certificate present, but not private key file \"%s\"\n"),
|
||||
fnbuf);
|
||||
return 0;
|
||||
}
|
||||
#ifndef WIN32
|
||||
if (!S_ISREG(buf.st_mode) || (buf.st_mode & 0077) ||
|
||||
buf.st_uid != geteuid())
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("private key file \"%s\" has wrong permissions\n"),
|
||||
fnbuf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if ((fp = fopen(fnbuf, "r")) == NULL)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not open private key file \"%s\": %s\n"),
|
||||
fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
|
||||
return 0;
|
||||
}
|
||||
#ifndef WIN32
|
||||
if (fstat(fileno(fp), &buf2) == -1 ||
|
||||
buf.st_dev != buf2.st_dev || buf.st_ino != buf2.st_ino)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (PEM_read_PrivateKey(fp, pkey, NULL, NULL) == NULL)
|
||||
{
|
||||
char *err = SSLerrmessage();
|
||||
/* read the user key from engine */
|
||||
char *engine_env = getenv("PGSSLKEY");
|
||||
char *engine_colon = strchr(engine_env, ':');
|
||||
char *engine_str;
|
||||
ENGINE *engine_ptr = NULL;
|
||||
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not read private key file \"%s\": %s\n"),
|
||||
fnbuf, err);
|
||||
SSLerrfree(err);
|
||||
if (!engine_colon)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("invalid value of PGSSLKEY environment variable\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
engine_str = malloc(engine_colon - engine_env + 1);
|
||||
strlcpy(engine_str, engine_env, engine_colon - engine_env + 1);
|
||||
if ((engine_ptr = ENGINE_by_id(engine_str)) == NULL)
|
||||
{
|
||||
char *err = SSLerrmessage();
|
||||
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not load SSL engine \"%s\":%s\n"), engine_str, err);
|
||||
free(engine_str);
|
||||
SSLerrfree(err);
|
||||
return 0;
|
||||
}
|
||||
if ((*pkey = ENGINE_load_private_key(engine_ptr,
|
||||
engine_colon + 1, NULL, NULL)) == NULL)
|
||||
{
|
||||
char *err = SSLerrmessage();
|
||||
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not read private SSL key %s from engine \"%s\": %s\n"),
|
||||
engine_colon + 1, engine_str, err);
|
||||
SSLerrfree(err);
|
||||
free(engine_str);
|
||||
return 0;
|
||||
}
|
||||
free(engine_str);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* read the user key from file*/
|
||||
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);
|
||||
if (stat(fnbuf, &buf) == -1)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("certificate present, but not private key file \"%s\"\n"),
|
||||
fnbuf);
|
||||
return 0;
|
||||
}
|
||||
#ifndef WIN32
|
||||
if (!S_ISREG(buf.st_mode) || (buf.st_mode & 0077) ||
|
||||
buf.st_uid != geteuid())
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("private key file \"%s\" has wrong permissions\n"),
|
||||
fnbuf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if ((fp = fopen(fnbuf, "r")) == NULL)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not open private key file \"%s\": %s\n"),
|
||||
fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
|
||||
return 0;
|
||||
}
|
||||
#ifndef WIN32
|
||||
if (fstat(fileno(fp), &buf2) == -1 ||
|
||||
buf.st_dev != buf2.st_dev || buf.st_ino != buf2.st_ino)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (PEM_read_PrivateKey(fp, pkey, NULL, NULL) == NULL)
|
||||
{
|
||||
char *err = SSLerrmessage();
|
||||
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not read private key file \"%s\": %s\n"),
|
||||
fnbuf, err);
|
||||
SSLerrfree(err);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
/* verify that the cert and key go together */
|
||||
if (!X509_check_private_key(*x509, *pkey))
|
||||
{
|
||||
@ -737,6 +788,9 @@ init_ssl_system(PGconn *conn)
|
||||
{
|
||||
if (pq_initssllib)
|
||||
{
|
||||
#if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
|
||||
OPENSSL_config(NULL);
|
||||
#endif
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user