Re: SSL enhancement patch ver.2 - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: SSL enhancement patch ver.2 |
Date | |
Msg-id | 200702160300.l1G30b725681@momjian.us Whole thread Raw |
In response to | SSL enhancement patch ver.2 ("Victor B. Wagner" <vitus@cryptocom.ru>) |
List | pgsql-patches |
Patch applied --- 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 I adjusted the documentation wording and some of the single-letter variable names you used --- the applied verison is attached. Thanks. --------------------------------------------------------------------------- Victor B. Wagner wrote: > This patch adds following functionality to PostgreSQL > > 1. If PostgreSQL is compiled with OpenSSL version 0.9.7 and above, > both backend and libpq read site-wide OpenSSL configuration file as > described in OPENSSL_config functon manual page. > > This allows to use hardware crypto acceleration modules (engines) and, > in future version 0.9.9 would allow to use additional cryptoalgorithms > (i.e. national standards) which are not included in core OpenSSL. > > All other configuration parameters which are supported by OpenSSL > library also are taken into account. > > > 2. New configuration option "ssl_ciphers" is added to postgresql.conf. > This option allows to change list of ciphers, acceptable by backend > during SSL connection. Changing list of ciphers can be desirable to > tighten or relax security of particular installation, and allows quick > fix on configuration file level in case if vulnerability is discovered > in one of cryptoalgorithms or their OpenSSL implementation - cipher > suites which use such algorithm can be easily disabled. > > > 3. If libpq compiled with OpenSSL 0.9.7 and above, compiled with engine > support, it is possible to store secret key of client certificate on the > hardware token, supported by one of OpenSSL engines (Hardware Security > Module). Name of engine which supports token and engine-specific key ID > are specifyed using environment variable PGSSLKEY. > > This allows use of hardware tokens such as smartcards to identify > clients, connecting to database. > > This functionality can be used in installations with high security > requirements or in situations where several people can use same terminal > (such as cash register in shops or malls). > > If PostgreSQL is compiled with version of OpenSSL which do not support > engines or doesn't have OPENSSL_config function, related functionality > is excluded by preprocessor conditionals, based on value of > SSLEAY_VERSION_NUMBER preprocessor symbol which is defined by all > versions of OpenSSL. > [ Attachment, skipping... ] > > ---------------------------(end of broadcast)--------------------------- > TIP 5: don't forget to increase your free space map settings -- Bruce Momjian <bruce@momjian.us> http://momjian.us EnterpriseDB http://www.enterprisedb.com + If your life is a hard drive, Christ can be your backup. + Index: doc/src/sgml/config.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/config.sgml,v retrieving revision 1.110 diff -c -c -r1.110 config.sgml *** doc/src/sgml/config.sgml 8 Feb 2007 15:46:03 -0000 1.110 --- doc/src/sgml/config.sgml 16 Feb 2007 01:26:20 -0000 *************** *** 569,574 **** --- 569,588 ---- </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> Index: doc/src/sgml/libpq.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v retrieving revision 1.228 diff -c -c -r1.228 libpq.sgml *** doc/src/sgml/libpq.sgml 6 Feb 2007 03:03:11 -0000 1.228 --- doc/src/sgml/libpq.sgml 16 Feb 2007 01:26:22 -0000 *************** *** 4175,4180 **** --- 4175,4192 ---- <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> <envar>PGKRBSRVNAME</envar> sets the Kerberos service name to use when *************** *** 4438,4457 **** for increased security. See <xref linkend="ssl-tcp"> for details about the server-side <acronym>SSL</> functionality. </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. (On Microsoft Windows these files are named <filename>%APPDATA%\postgresql\postgresql.crt</filename> and <filename>%APPDATA%\postgresql\postgresql.key</filename>.) </para> <para> If the file <filename>~/.postgresql/root.crt</> is present in the user's home directory, <application>libpq</application> will use the certificate list stored --- 4450,4494 ---- 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, 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, <application>libpq</application> will use the certificate list stored Index: doc/src/sgml/runtime.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v retrieving revision 1.376 diff -c -c -r1.376 runtime.sgml *** doc/src/sgml/runtime.sgml 1 Feb 2007 00:28:18 -0000 1.376 --- doc/src/sgml/runtime.sgml 16 Feb 2007 01:26:23 -0000 *************** *** 1516,1521 **** --- 1516,1540 ---- </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 self-signed certificate can be used for testing, but a *************** *** 1528,1535 **** <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 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 --- 1547,1554 ---- <programlisting> openssl req -new -text -out server.req </programlisting> ! 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 Index: src/backend/libpq/be-secure.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v retrieving revision 1.77 diff -c -c -r1.77 be-secure.c *** src/backend/libpq/be-secure.c 7 Feb 2007 00:52:35 -0000 1.77 --- src/backend/libpq/be-secure.c 16 Feb 2007 01:26:24 -0000 *************** *** 92,97 **** --- 92,101 ---- #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,130 **** --- 129,138 ---- #define RENEGOTIATION_LIMIT (512 * 1024 * 1024) static SSL_CTX *SSL_context = NULL; + + /* GUC variable controlling SSL cipher list*/ + extern char *SSLCipherSuites; + #endif /* ------------------------------------------------------------ */ *************** *** 719,724 **** --- 727,735 ---- 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,786 **** 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) elog(FATAL, "could not set the cipher list (no valid ciphers available)"); /* --- 791,797 ---- 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, SSLCipherSuites) != 1) elog(FATAL, "could not set the cipher list (no valid ciphers available)"); /* Index: src/backend/postmaster/postmaster.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v retrieving revision 1.521 diff -c -c -r1.521 postmaster.c *** src/backend/postmaster/postmaster.c 13 Feb 2007 19:18:54 -0000 1.521 --- src/backend/postmaster/postmaster.c 16 Feb 2007 01:26:25 -0000 *************** *** 186,191 **** --- 186,192 ---- /* still more option variables */ bool EnableSSL = false; + char *SSLCipherSuites; bool SilentMode = false; /* silent mode (-S) */ int PreAuthDelay = 0; Index: src/backend/utils/misc/guc.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v retrieving revision 1.374 diff -c -c -r1.374 guc.c *** src/backend/utils/misc/guc.c 14 Feb 2007 03:08:44 -0000 1.374 --- src/backend/utils/misc/guc.c 16 Feb 2007 01:26:28 -0000 *************** *** 2314,2319 **** --- 2314,2329 ---- 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 Index: src/backend/utils/misc/postgresql.conf.sample =================================================================== RCS file: /cvsroot/pgsql/src/backend/utils/misc/postgresql.conf.sample,v retrieving revision 1.207 diff -c -c -r1.207 postgresql.conf.sample *** src/backend/utils/misc/postgresql.conf.sample 25 Jan 2007 15:05:15 -0000 1.207 --- src/backend/utils/misc/postgresql.conf.sample 16 Feb 2007 01:26:28 -0000 *************** *** 74,79 **** --- 74,80 ---- #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 Index: src/include/postmaster/postmaster.h =================================================================== RCS file: /cvsroot/pgsql/src/include/postmaster/postmaster.h,v retrieving revision 1.15 diff -c -c -r1.15 postmaster.h *** src/include/postmaster/postmaster.h 5 Jan 2007 22:19:57 -0000 1.15 --- src/include/postmaster/postmaster.h 16 Feb 2007 01:26:28 -0000 *************** *** 15,20 **** --- 15,21 ---- /* GUC options */ extern bool EnableSSL; + extern char *SSLCipherSuites; extern bool SilentMode; extern int ReservedBackends; extern int PostPortNumber; Index: src/interfaces/libpq/fe-secure.c =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-secure.c,v retrieving revision 1.92 diff -c -c -r1.92 fe-secure.c *** src/interfaces/libpq/fe-secure.c 8 Feb 2007 11:10:27 -0000 1.92 --- src/interfaces/libpq/fe-secure.c 16 Feb 2007 01:26:29 -0000 *************** *** 111,116 **** --- 111,122 ---- #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,659 **** } fclose(fp); ! /* read the user key */ ! 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); - /* verify that the cert and key go together */ if (!X509_check_private_key(*x509, *pkey)) { --- 612,710 ---- } fclose(fp); ! #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE) ! if (getenv("PGSSLKEY")) { ! /* read the user key from engine */ ! char *engine_env = getenv("PGSSLKEY"); ! char *engine_colon = strchr(engine_env, ':'); ! char *engine_str; ! ENGINE *engine_ptr = NULL; ! ! 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); } /* verify that the cert and key go together */ if (!X509_check_private_key(*x509, *pkey)) { *************** *** 737,742 **** --- 788,796 ---- { if (pq_initssllib) { + #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) + OPENSSL_config(NULL); + #endif SSL_library_init(); SSL_load_error_strings(); }
pgsql-patches by date: