dovecot-2.2: login-common: Add support for ECDH/ECDHE cipher suites

dovecot at dovecot.org dovecot at dovecot.org
Wed Jul 10 08:37:47 EEST 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/331d0a4fe772
changeset: 16587:331d0a4fe772
user:      David Hicks <david at hicks.id.au>
date:      Sat Jul 06 14:46:16 2013 +1000
description:
login-common: Add support for ECDH/ECDHE cipher suites

ECDH temporary key parameter selection must be performed during OpenSSL
context initialisation before ECDH and ECDHE cipher suites can be used.

OpenSSL >= 1.0.2 automatically handles ECDH temporary key parameter selection.
For OpenSSL < 1.0.2 we must manually specify a named elliptic curve that
Dovecot will use to generate an ephemeral key pair. By default we try to use
the same named curve as that used in the server's private EC key file. If this
attempt fails, a fall back curve of NIST P-384 (secp384r1) is used instead.

RFC 6460 states that NIST P-384 MUST be used for cipher suites that include
AES-256. For cipher suites that include AES-128, RFC 6460 states that NIST
P-256 MUST be used. No matter which curve is used as a fall back option,
Dovecot will be non-compliant. The reason for selecting NIST P-384 as a fall
back curve is to ensure that the non-compliance is in the form of providing
too great a level of security for AES-128 cipher suites rather than too little
security for AES-256 cipher suites.

diffstat:

 src/login-common/ssl-proxy-openssl.c |  76 +++++++++++++++++++++++++++++++++++-
 1 files changed, 74 insertions(+), 2 deletions(-)

diffs (111 lines):

diff -r 620876853f6f -r 331d0a4fe772 src/login-common/ssl-proxy-openssl.c
--- a/src/login-common/ssl-proxy-openssl.c	Wed Jul 10 06:54:57 2013 +0300
+++ b/src/login-common/ssl-proxy-openssl.c	Sat Jul 06 14:46:16 2013 +1000
@@ -119,6 +119,10 @@
 			const struct master_service_ssl_settings *ssl_set);
 static void ssl_server_context_deinit(struct ssl_server_context **_ctx);
 
+static void ssl_proxy_ctx_set_crypto_params(SSL_CTX *ssl_ctx,
+                                            const struct master_service_ssl_settings *set);
+static int ssl_proxy_ctx_get_pkey_ec_curve_name(const struct master_service_ssl_settings *set);
+
 static unsigned int ssl_server_context_hash(const struct ssl_server_context *ctx)
 {
 	unsigned int i, g, h = 0;
@@ -993,11 +997,58 @@
 		store = SSL_CTX_get_cert_store(ssl_ctx);
 		load_ca(store, set->ssl_ca, load_xnames ? &xnames : NULL);
 	}
+	ssl_proxy_ctx_set_crypto_params(ssl_ctx, set);
 	SSL_CTX_set_info_callback(ssl_ctx, ssl_info_callback);
+	return xnames;
+}
+
+static void
+ssl_proxy_ctx_set_crypto_params(SSL_CTX *ssl_ctx,
+                                const struct master_service_ssl_settings *set)
+{
+#if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L
+	EC_KEY *ecdh;
+	int nid;
+	const char *curve_name;
+#endif
 	if (SSL_CTX_need_tmp_RSA(ssl_ctx))
 		SSL_CTX_set_tmp_rsa_callback(ssl_ctx, ssl_gen_rsa_key);
 	SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_tmp_dh_callback);
-	return xnames;
+#if !defined(OPENSSL_NO_ECDH)
+	/* In the non-recommended situation where ECDH cipher suites are being
+	   used instead of ECDHE, do not reuse the same ECDH key pair for
+	   different sessions. This option improves forward secrecy. */
+	SSL_CTX_set_options(ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
+#endif
+#if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10002000L
+	/* OpenSSL >= 1.0.2 automatically handles ECDH temporary key parameter
+	   selection. */
+	SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
+#elif !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L
+	/* For OpenSSL < 1.0.2, ECDH temporary key parameter selection must be
+	   performed manually. Attempt to select the same curve as that used
+	   in the server's private EC key file. Otherwise fall back to the
+	   NIST P-384 (secp384r1) curve to be compliant with RFC 6460 when
+	   AES-256 TLS cipher suites are in use. This fall back option does
+	   however make Dovecot non-compliant with RFC 6460 which requires
+	   curve NIST P-256 (prime256v1) be used when AES-128 TLS cipher
+	   suites are in use. At least the non-compliance is in the form of
+	   providing too much security rather than too little. */
+	nid = ssl_proxy_ctx_get_pkey_ec_curve_name(set);
+	ecdh = EC_KEY_new_by_curve_name(nid);
+	if (ecdh == NULL) {
+		/* Fall back option */
+		nid = NID_secp384r1;
+		ecdh = EC_KEY_new_by_curve_name(nid);
+	}
+	if ((curve_name = OBJ_nid2sn(nid)) != NULL && set->verbose_ssl)
+		i_debug("SSL: elliptic curve %s will be used for ECDH and"
+		        " ECDHE key exchanges", curve_name);
+	if (ecdh != NULL) {
+		SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
+		EC_KEY_free(ecdh);
+	}
+#endif
 }
 
 static void
@@ -1084,6 +1135,28 @@
 }
 
 static int
+ssl_proxy_ctx_get_pkey_ec_curve_name(const struct master_service_ssl_settings *set)
+{
+	int nid = 0;
+#if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L
+	EVP_PKEY *pkey;
+	const char *password;
+	EC_KEY *eckey;
+	const EC_GROUP *ecgrp;
+
+	password = *set->ssl_key_password != '\0' ? set->ssl_key_password :
+		getenv(MASTER_SSL_KEY_PASSWORD_ENV);
+	pkey = ssl_proxy_load_key(set->ssl_key, password);
+	if (pkey != NULL &&
+	    (eckey = EVP_PKEY_get1_EC_KEY(pkey)) != NULL &&
+	    (ecgrp = EC_KEY_get0_group(eckey)) != NULL)
+		nid = EC_GROUP_get_curve_name(ecgrp);
+	EVP_PKEY_free(pkey);
+#endif
+	return nid;
+}
+
+static int
 ssl_proxy_ctx_use_certificate_chain(SSL_CTX *ctx, const char *cert)
 {
 	/* mostly just copy&pasted from SSL_CTX_use_certificate_chain_file() */
@@ -1209,7 +1282,6 @@
 #endif
 
 	ssl_proxy_ctx_use_key(ctx->ctx, ssl_set);
-	SSL_CTX_set_info_callback(ctx->ctx, ssl_info_callback);
 
 	if (ctx->verify_client_cert)
 		ssl_proxy_ctx_verify_client(ctx->ctx, xnames);


More information about the dovecot-cvs mailing list