------------------------------------------------------------ revno: 13966 revision-id: squid3@treenet.co.nz-20151222075423-acprzy6amd0zj1yx parent: squid3@treenet.co.nz-20151222025942-v6x4kua6sor5pnea author: Paulo Matias committer: Amos Jeffries branch nick: 3.5 timestamp: Tue 2015-12-22 20:54:23 +1300 message: 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. ------------------------------------------------------------ # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: squid3@treenet.co.nz-20151222075423-acprzy6amd0zj1yx # target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5 # testament_sha1: b4f09f6891582f67e9d1c13620e657d740f3bd27 # timestamp: 2015-12-22 08:20:48 +0000 # source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5 # base_revision_id: squid3@treenet.co.nz-20151222025942-\ # v6x4kua6sor5pnea # # Begin patch === modified file 'src/anyp/PortCfg.cc' --- src/anyp/PortCfg.cc 2015-01-18 04:20:58 +0000 +++ src/anyp/PortCfg.cc 2015-12-22 07:54:23 +0000 @@ -53,6 +53,7 @@ capath(NULL), crlfile(NULL), dhfile(NULL), + tls_dh(NULL), sslflags(NULL), sslContextSessionId(NULL), generateHostCertificates(false), @@ -66,6 +67,7 @@ clientVerifyCrls(), clientCA(), dhParams(), + eecdhCurve(NULL), contextMethod(), sslContextFlags(0), sslOptions(0) @@ -94,8 +96,10 @@ safe_free(capath); safe_free(crlfile); safe_free(dhfile); + safe_free(tls_dh); safe_free(sslflags); safe_free(sslContextSessionId); + safe_free(eecdhCurve); #endif } @@ -139,6 +143,8 @@ 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) @@ -192,8 +198,23 @@ if (!contextMethod) fatalf("Unable to compute context method to use"); - 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); === modified file 'src/anyp/PortCfg.h' --- src/anyp/PortCfg.h 2015-01-13 09:13:49 +0000 +++ src/anyp/PortCfg.h 2015-12-22 07:54:23 +0000 @@ -78,6 +78,7 @@ 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 @@ 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 === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2015-12-18 11:11:53 +0000 +++ src/cache_cf.cc 2015-12-22 07:54:23 +0000 @@ -3754,8 +3754,13 @@ 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); @@ -3979,6 +3984,9 @@ 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); === modified file 'src/cf.data.pre' --- src/cf.data.pre 2015-12-18 11:11:53 +0000 +++ src/cf.data.pre 2015-12-22 07:54:23 +0000 @@ -1824,6 +1824,12 @@ SINGLE_DH_USE Always create a new key when using temporary/ephemeral DH key exchanges NO_TICKET Disables TLS tickets extension + + SINGLE_ECDH_USE + Enable ephemeral ECDH key exchange. + The adopted curve should be specified + using the tls-dh option. + ALL Enable various bug workarounds suggested as "harmless" by OpenSSL Be warned that this reduces SSL/TLS @@ -1845,11 +1851,15 @@ 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 @@ -1988,8 +1998,15 @@ NO_SSLv2 Disallow the use of SSLv2 NO_SSLv3 Disallow the use of SSLv3 NO_TLSv1 Disallow the use of TLSv1 + SINGLE_DH_USE 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. + See src/ssl_support.c or OpenSSL SSL_CTX_set_options documentation for a complete list of options. @@ -2007,8 +2024,10 @@ 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 === modified file 'src/ssl/support.cc' --- src/ssl/support.cc 2015-12-22 02:59:42 +0000 +++ src/ssl/support.cc 2015-12-22 07:54:23 +0000 @@ -493,6 +493,11 @@ "NO_TICKET", SSL_OP_NO_TICKET }, #endif +#if SSL_OP_SINGLE_ECDH_USE + { + "SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE + }, +#endif { "", 0 }, @@ -853,6 +858,29 @@ #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) { int ssl_error; @@ -888,6 +916,16 @@ 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;