This sets up ECDH key exchange, when compiling against OpenSSL
that supports EC.  Then ECDHE-RSA and ECDHE-ECDSA ciphersuites
can be used for SSL connections.  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.

Quick test with single-threaded client connecting repeatedly
to server on same machine, then closes connection.  Measured
is connections-per-second.

  Key             DHE     ECDHE
  RSA-1024        177.5   278.1   (x 1.56)
  RSA-2048        140.5   191.1   (x 1.36)
  RSA-4096        59.5    67.3    (x 1.13)
  ECDSA-256               280.7   (~ RSA-3072)
  ECDSA-384               128.9   (~ RSA-7680)

There is also new GUC option - ssl_ecdh_curve - that specifies
curve name used for ECDH.  It defaults to "prime256v1", which
is the most common curve in use in HTTPS.  According to NIST
should be securitywise similar to ~3072 bit RSA/DH.
(http://www.keylength.com / NIST Recommendations).

Other commonly-implemented curves are secp384r1 and secp521r1
(OpenSSL names).  The rest are not recommended as EC curves
needed to be exchanged by name and need to be explicitly
supprted by both client and server.  TLS does have free-form
curve exchange, but few client libraries implement that,
at least OpenSSL does not.

Full list can be seen with "openssl ecparam -list_curves".

It does not tune ECDH curve with key size automatically,
like DHE does.  The reason is the curve naming situation.
---
 doc/src/sgml/config.sgml      | 13 +++++++++++++
 src/backend/libpq/be-secure.c | 32 ++++++++++++++++++++++++++++++++
 src/backend/utils/misc/guc.c  | 16 ++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 56bfa01..3785052 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -895,6 +895,19 @@ 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 name of EC curve which will be used in ECDH key excanges.
+        Default is <literal>prime256p1</>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-password-encryption" xreflabel="password_encryption">
       <term><varname>password_encryption</varname> (<type>boolean</type>)</term>
       <indexterm>
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 2094674..8d688f2 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -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;
 
@@ -765,6 +771,29 @@ 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)
+		elog(FATAL, "ECDH: curve not known: %s", SSLECDHCurve);
+
+	ecdh = EC_KEY_new_by_curve_name(nid);
+	if (!ecdh)
+		elog(FATAL, "ECDH: failed to allocate 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.
  */
@@ -844,6 +873,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)");
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 7f1771a..defd44a 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -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
@@ -3151,6 +3152,21 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"ssl_ecdh_curve", PGC_POSTMASTER, CONN_AUTH_SECURITY,
+			gettext_noop("Sets the list of EC curve used 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."),
 			NULL,
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to