]> granicus.if.org Git - postgresql/commitdiff
SSL: Support ECDH key exchange
authorPeter Eisentraut <peter_e@gmx.net>
Sat, 7 Dec 2013 20:11:44 +0000 (15:11 -0500)
committerPeter Eisentraut <peter_e@gmx.net>
Sat, 7 Dec 2013 20:11:44 +0000 (15:11 -0500)
This sets up ECDH key exchange, when compiling against OpenSSL that
supports EC.  Then the ECDHE-RSA and ECDHE-ECDSA cipher suites can be
used for SSL connections.  The latter one means that EC keys are now
usable.

The reason for EC key exchange is that it's faster than DHE and it
allows to go to higher security levels where RSA will be horribly slow.

There is also new GUC option ssl_ecdh_curve that specifies the curve
name used for ECDH.  It defaults to "prime256v1", which is the most
common curve in use in HTTPS.

From: Marko Kreen <markokr@gmail.com>
Reviewed-by: Adrian Klaver <adrian.klaver@gmail.com>
doc/src/sgml/config.sgml
src/backend/libpq/be-secure.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample

index 1946bb083d92f453e242aedf764747d2dc95ee6d..fee83c1496b0a742bf1dfcfbbca83f662be0daa4 100644 (file)
@@ -907,6 +907,24 @@ include 'filename'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-ssl-ecdh-curve" xreflabel="ssl_ecdh_curve">
+      <term><varname>ssl_ecdh_curve</varname> (<type>string</type>)</term>
+      <indexterm>
+       <primary><varname>ssl_ecdh_curve</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies the name of the curve to use in ECDH key exchanges.  The
+        default is <literal>prime256p1</>.
+       </para>
+
+       <para>
+        The list of available curves can be shown with the command
+        <literal>openssl ecparam -list_curves</literal>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-password-encryption" xreflabel="password_encryption">
       <term><varname>password_encryption</varname> (<type>boolean</type>)</term>
       <indexterm>
index 51f3b12bb97e6c4cfc21999fcce276b23ed5f63d..43633e7a316da4c2f7ffba41d98d32e010b1ba86 100644 (file)
@@ -69,6 +69,9 @@
 #if SSLEAY_VERSION_NUMBER >= 0x0907000L
 #include <openssl/conf.h>
 #endif
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH)
+#include <openssl/ec.h>
+#endif
 #endif   /* USE_SSL */
 
 #include "libpq/libpq.h"
@@ -112,6 +115,9 @@ static bool ssl_loaded_verify_locations = false;
 /* GUC variable controlling SSL cipher list */
 char      *SSLCipherSuites = NULL;
 
+/* GUC variable for default ECHD curve. */
+char      *SSLECDHCurve;
+
 /* GUC variable: if false, prefer client ciphers */
 bool      SSLPreferServerCiphers;
 
@@ -774,6 +780,31 @@ info_cb(const SSL *ssl, int type, int args)
        }
 }
 
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH)
+static void
+initialize_ecdh(void)
+{
+       EC_KEY     *ecdh;
+       int                     nid;
+
+       nid = OBJ_sn2nid(SSLECDHCurve);
+       if (!nid)
+               ereport(FATAL,
+                               (errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve)));
+
+       ecdh = EC_KEY_new_by_curve_name(nid);
+       if (!ecdh)
+               ereport(FATAL,
+                               (errmsg("ECDH: could not create key")));
+
+       SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_ECDH_USE);
+       SSL_CTX_set_tmp_ecdh(SSL_context, ecdh);
+       EC_KEY_free(ecdh);
+}
+#else
+#define initialize_ecdh()
+#endif
+
 /*
  *     Initialize global SSL context.
  */
@@ -853,6 +884,9 @@ initialize_SSL(void)
        SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb);
        SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2);
 
+       /* set up ephemeral ECDH keys */
+       initialize_ecdh();
+
        /* 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)");
index 5c39de5a522e8a87e44a42cc0bbfa61bd3003570..f3bf6e0aa2fce7e66a775beeed8aa0ee15ac291f 100644 (file)
@@ -127,6 +127,7 @@ extern char *temp_tablespaces;
 extern bool ignore_checksum_failure;
 extern bool synchronize_seqscans;
 extern char *SSLCipherSuites;
+extern char *SSLECDHCurve;
 extern bool SSLPreferServerCiphers;
 
 #ifdef TRACE_SORT
@@ -3150,6 +3151,21 @@ static struct config_string ConfigureNamesString[] =
                NULL, NULL, NULL
        },
 
+       {
+               {"ssl_ecdh_curve", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+                       gettext_noop("Sets the curve to use for ECDH."),
+                       NULL,
+                       GUC_SUPERUSER_ONLY
+               },
+               &SSLECDHCurve,
+#ifdef USE_SSL
+               "prime256v1",
+#else
+               "none",
+#endif
+               NULL, NULL, NULL
+       },
+
        {
                {"application_name", PGC_USERSET, LOGGING_WHAT,
                        gettext_noop("Sets the application name to be reported in statistics and logs."),
index a0f564bb9cf6634f40a0bbf92344d46c71dbfec4..983cae7fda24c2656937cc6b942ac52abbc12fa5 100644 (file)
@@ -82,6 +82,7 @@
 #ssl_ciphers = 'DEFAULT:!LOW:!EXP:!MD5:@STRENGTH'      # allowed SSL ciphers
                                        # (change requires restart)
 #ssl_prefer_server_ciphers = on                # (change requires restart)
+#ssl_ecdh_curve = 'prime256v1'         # (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)