From: Paulo Matias Date: Fri, 19 Jun 2015 04:57:39 +0000 (-0700) Subject: Support Ephemeral Elliptic Curve Diffie-Hellman (EECDH) key exchange X-Git-Tag: merge-candidate-3-v1~79 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=54fbe371a5e2b1ab6a78ea60b72581842817c969;p=thirdparty%2Fsquid.git Support Ephemeral Elliptic Curve Diffie-Hellman (EECDH) key exchange Which allows for forward secrecy with better performance than traditional ephemeral DH. Also replaces http(s)_port dhparams= option with tls-dh= that takes a curve name as well as filename for curve parameters. --- diff --git a/doc/release-notes/release-4.sgml b/doc/release-notes/release-4.sgml index d31db9d573..2917065764 100644 --- a/doc/release-notes/release-4.sgml +++ b/doc/release-notes/release-4.sgml @@ -137,6 +137,12 @@ This section gives a thorough account of those changes in three categories:

All options= values for SSLv2 configuration or disabling have been removed.

Removed version= option. Use options= instead. +

New options=SINGLE_ECDH_USE parameter to enable ephemeral + ECDH key exchange. +

Deprecated dhparams= option. Use tls-dh= instead. + The new option allows to optionally specify an elliptic curve for + ephemeral ECDH by adding curve-name: in front of the + parameter file name.

Manual squid.conf update may be required on upgrade. sslcrtd_children diff --git a/src/anyp/PortCfg.cc b/src/anyp/PortCfg.cc index 9876273eb7..26a10e3f2f 100644 --- a/src/anyp/PortCfg.cc +++ b/src/anyp/PortCfg.cc @@ -54,6 +54,7 @@ AnyP::PortCfg::PortCfg() : capath(NULL), crlfile(NULL), dhfile(NULL), + tls_dh(NULL), sslflags(NULL), sslContextSessionId(NULL), generateHostCertificates(false), @@ -67,6 +68,7 @@ AnyP::PortCfg::PortCfg() : clientVerifyCrls(), clientCA(), dhParams(), + eecdhCurve(NULL), contextMethod(), sslContextFlags(0), sslOptions(0) @@ -95,8 +97,10 @@ AnyP::PortCfg::~PortCfg() safe_free(capath); safe_free(crlfile); safe_free(dhfile); + safe_free(tls_dh); safe_free(sslflags); safe_free(sslContextSessionId); + safe_free(eecdhCurve); #endif } @@ -140,6 +144,8 @@ AnyP::PortCfg::clone() const b->crlfile = xstrdup(crlfile); if (dhfile) b->dhfile = xstrdup(dhfile); + if (tls_dh) + b->tls_dh = xstrdup(tls_dh); if (sslflags) b->sslflags = xstrdup(sslflags); if (sslContextSessionId) @@ -227,8 +233,23 @@ AnyP::PortCfg::configureSslServerContext() contextMethod = SSLv23_server_method(); #endif - if (dhfile) - dhParams.reset(Ssl::readDHParams(dhfile)); + const char *dhParamsFile = dhfile; // backward compatibility for dhparams= configuration + safe_free(eecdhCurve); // clear any previous EECDH configuration + if (tls_dh && *tls_dh) { + eecdhCurve = xstrdup(tls_dh); + char *p = strchr(eecdhCurve, ':'); + if (p) { // tls-dh=eecdhCurve:dhParamsFile + *p = '\0'; + dhParamsFile = p+1; + } else { // tls-dh=dhParamsFile + dhParamsFile = tls_dh; + // a NULL eecdhCurve means "do not use EECDH" + safe_free(eecdhCurve); + } + } + + if (dhParamsFile && *dhParamsFile) + dhParams.reset(Ssl::readDHParams(dhParamsFile)); if (sslflags) sslContextFlags = Ssl::parse_flags(sslflags); diff --git a/src/anyp/PortCfg.h b/src/anyp/PortCfg.h index f4f3d9e6f4..66670ebb43 100644 --- a/src/anyp/PortCfg.h +++ b/src/anyp/PortCfg.h @@ -78,6 +78,7 @@ public: char *capath; char *crlfile; char *dhfile; + char *tls_dh; char *sslflags; char *sslContextSessionId; ///< "session id context" for staticSslContext bool generateHostCertificates; ///< dynamically make host cert for sslBump @@ -93,6 +94,7 @@ public: Ssl::X509_CRL_STACK_Pointer clientVerifyCrls; ///< additional CRL lists to use when verifying the client certificate Ssl::X509_NAME_STACK_Pointer clientCA; ///< CA certificates to use when verifying client certificates Ssl::DH_Pointer dhParams; ///< DH parameters for temporary/ephemeral DH key exchanges + char *eecdhCurve; ///< Elliptic curve for ephemeral EC-based DH key exchanges Ssl::ContextMethod contextMethod; ///< The context method (SSL_METHOD) to use when creating certificates long sslContextFlags; ///< flags modifying the use of SSL long sslOptions; ///< SSL engine options diff --git a/src/cache_cf.cc b/src/cache_cf.cc index d8ee3f03c0..a4bc03682d 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -3612,8 +3612,13 @@ parse_port_option(AnyP::PortCfgPointer &s, char *token) safe_free(s->crlfile); s->crlfile = xstrdup(token + 8); } else if (strncmp(token, "dhparams=", 9) == 0) { + debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: '" << token << "' is deprecated " << + "in " << cfg_directive << ". Use 'tls-dh=' instead."); safe_free(s->dhfile); s->dhfile = xstrdup(token + 9); + } else if (strncmp(token, "tls-dh=", 7) == 0) { + safe_free(s->tls_dh); + s->tls_dh = xstrdup(token + 7); } else if (strncmp(token, "sslflags=", 9) == 0) { safe_free(s->sslflags); s->sslflags = xstrdup(token + 9); @@ -3834,6 +3839,9 @@ dump_generic_port(StoreEntry * e, const char *n, const AnyP::PortCfgPointer &s) if (s->dhfile) storeAppendPrintf(e, " dhparams=%s", s->dhfile); + if (s->tls_dh) + storeAppendPrintf(e, " tls-dh=%s", s->tls_dh); + if (s->sslflags) storeAppendPrintf(e, " sslflags=%s", s->sslflags); diff --git a/src/cf.data.pre b/src/cf.data.pre index 07713be530..e4320d0d3f 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -1935,6 +1935,11 @@ DOC_START Always create a new key when using temporary/ephemeral DH key exchanges + SINGLE_ECDH_USE + Enable ephemeral ECDH key exchange. + The adopted curve should be specified + using the tls-dh option. + NO_TICKET Disable use of RFC5077 session tickets. Some servers may have problems @@ -1963,11 +1968,15 @@ DOC_START the client certificate, in addition to CRLs stored in the capath. Implies VERIFY_CRL flag below. - dhparams= File containing DH parameters for temporary/ephemeral - DH key exchanges. See OpenSSL documentation for details - on how to create this file. - WARNING: EDH ciphers will be silently disabled if this - option is not set. + tls-dh=[curve:]file + File containing DH parameters for temporary/ephemeral DH key + exchanges, optionally prefixed by a curve for ephemeral ECDH + key exchanges. + See OpenSSL documentation for details on how to create the + DH parameter file. Supported curves for ECDH can be listed + using the "openssl ecparam -list_curves" command. + WARNING: EDH and EECDH ciphers will be silently disabled if + this option is not set. sslflags= Various flags modifying the use of SSL: DELAYED_AUTH @@ -2110,6 +2119,11 @@ DOC_START Always create a new key when using temporary/ephemeral DH key exchanges + SINGLE_ECDH_USE + Enable ephemeral ECDH key exchange. + The adopted curve should be specified + using the tls-dh option. + SSL_OP_NO_TICKET Disable use of RFC5077 session tickets. Some servers may have problems @@ -2138,8 +2152,10 @@ DOC_START the client certificate, in addition to CRLs stored in the capath. Implies VERIFY_CRL flag below. - dhparams= File containing DH parameters for temporary/ephemeral - DH key exchanges. + tls-dh=[curve:]file + File containing DH parameters for temporary/ephemeral DH key + exchanges, optionally prefixed by a curve for ephemeral ECDH + key exchanges. sslflags= Various flags modifying the use of SSL: DELAYED_AUTH diff --git a/src/ssl/support.cc b/src/ssl/support.cc index f8dcfbac68..f5d0696ef2 100644 --- a/src/ssl/support.cc +++ b/src/ssl/support.cc @@ -471,6 +471,11 @@ ssl_options[] = { { "NO_TICKET", SSL_OP_NO_TICKET }, +#endif +#if SSL_OP_SINGLE_ECDH_USE + { + "SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE + }, #endif { "", 0 @@ -835,6 +840,29 @@ ssl_info_cb(const SSL *ssl, int where, int ret) } #endif +static bool +configureSslEECDH(SSL_CTX *sslContext, const char *curve) +{ +#if OPENSSL_VERSION_NUMBER >= 0x0090800fL && !defined(OPENSSL_NO_ECDH) + int nid = OBJ_sn2nid(curve); + if (!nid) { + debugs(83, DBG_CRITICAL, "ERROR: Unknown EECDH curve '" << curve << "'"); + return false; + } + + EC_KEY *ecdh = EC_KEY_new_by_curve_name(nid); + if (ecdh == NULL) + return false; + + const bool ok = SSL_CTX_set_tmp_ecdh(sslContext, ecdh) != 0; + EC_KEY_free(ecdh); + return ok; +#else + debugs(83, DBG_CRITICAL, "ERROR: EECDH is not available in this build. Please link against OpenSSL>=0.9.8 and ensure OPENSSL_NO_ECDH is not set."); + return false; +#endif +} + static bool configureSslContext(SSL_CTX *sslContext, AnyP::PortCfg &port) { @@ -871,6 +899,16 @@ configureSslContext(SSL_CTX *sslContext, AnyP::PortCfg &port) debugs(83, 9, "Setting RSA key generation callback."); SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb); + if (port.eecdhCurve) { + debugs(83, 9, "Setting Ephemeral ECDH curve to " << port.eecdhCurve << "."); + + if (!configureSslEECDH(sslContext, port.eecdhCurve)) { + ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Unable to configure Ephemeral ECDH: " << ERR_error_string(ssl_error, NULL)); + return false; + } + } + debugs(83, 9, "Setting CA certificate locations."); const char *cafile = port.cafile ? port.cafile : port.clientca;