David Hicks
2013-Jul-06 09:50 UTC
[Dovecot] [PATCH] login-common: Add support for ECDH/ECDHE cipher suites
# HG changeset patch # User David Hicks <david at hicks.id.au> # Date 1373085976 -36000 # Sat Jul 06 14:46:16 2013 +1000 # Node ID ccd83f38e4b484ae18f69ea08631eefcaf6a4a4e # Parent 1fbac590b9d4dc05d81247515477bfe6192c262c 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. diff -r 1fbac590b9d4 -r ccd83f38e4b4 src/login-common/ssl-proxy-openssl.c --- a/src/login-common/ssl-proxy-openssl.c Fri Jun 28 19:48:37 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) + 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; + 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); -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: This is a digitally signed message part URL: <http://dovecot.org/pipermail/dovecot/attachments/20130706/26a2b8cb/attachment-0001.bin>
Timo Sirainen
2013-Jul-10 06:00 UTC
[Dovecot] [PATCH] login-common: Add support for ECDH/ECDHE cipher suites
On Sat, 2013-07-06 at 19:50 +1000, David Hicks wrote:> ECDH temporary key parameter selection must be performed during OpenSSL > context initialisation before ECDH and ECDHE cipher suites can be used.Thanks. Committed with two small changes: - added const to EC_GROUP to avoid warning - call i_debug() only with verbose_ssl The login-common/ssl-proxy-openssl.c will go away in some future version and be replaced by the code in lib-ssl-iostream. I added the code there as well: http://hg.dovecot.org/dovecot-2.2/rev/dc99912e5047
Reasonably Related Threads
- [PATCH] Fix for client certificate validation does not work
- openssl 1.1.0d breaks Android7 TLS connects
- [PATCH] Add support for lower TLS version than default
- 2.2.5 fails to compile - SSL_OP_SINGLE_ECDH_USE : Solaris 10 + Sunstudio 12.3
- IMAP and POP3 per SSL