I'd also like to see this issue fixed. The relevant upstream changes can be found at <https://svn.apache.org/r1527295>.
Changing the defaults has the potential to break old buggy clients, such as those using Java 6. So I would suggest that the Debian package continue to use the old default behavior (with a maximum of 1024 bits for DH), but backport the option to override this by specifying the parameters in the certificate file. (Which, to be honest, seems more than a little bit kludgy to me, but that is the approach upstream Apache is taking.) I don't know much of anything about Apache internals (or about OpenSSL, for that matter), but these changes look straightforward enough, so here is a patch that ought to do the job. I'm not sure how to check whether this patch is really working. 'openssl s_client' is my usual tool for testing such things, and it doesn't seem to have the option of displaying the parameters used for key exchange. However, I can see that if I specify a 2048-bit DH modulus in the certificate file, and use a DHE ciphersuite, the ServerKeyExchange and ClientKeyExchange packets are correspondingly larger. Likewise if I specify a larger curve and an ECDHE suite. Benjamin
Description: Allow custom DH and ECDH parameters. The parameters used for DH and ECDH are hard-coded by default, and the 1024-bit modulus used by default for DH may be too weak to provide effective forward secrecy for years to come. Following the behavior of Apache 2.4.7, allow the administrator to specify custom parameters by including them in the SSLCertificateFile. Origin: backport, subset of https://svn.apache.org/r1527295 Bug: https://bz.apache.org/bugzilla/show_bug.cgi?id=49559 Bug-Debian: http://bugs.debian.org/780398 --- apache2-2.2.22.orig/modules/ssl/ssl_engine_init.c +++ apache2-2.2.22/modules/ssl/ssl_engine_init.c @@ -1040,10 +1040,14 @@ static void ssl_init_server_certs(server const char *rsa_id, *dsa_id; #ifndef OPENSSL_NO_EC const char *ecc_id; + EC_GROUP *ecparams; + int nid; + EC_KEY *eckey; #endif const char *vhost_id = mctx->sc->vhost_id; int i; int have_rsa, have_dsa; + DH *dhparams; #ifndef OPENSSL_NO_EC int have_ecc; #endif @@ -1098,6 +1102,33 @@ static void ssl_init_server_certs(server #endif ssl_die(); } + + /* + * Try to read DH parameters from the (first) SSLCertificateFile + */ + if ((mctx->pks->cert_files[0] != NULL) && + (dhparams = ssl_dh_GetParamFromFile(mctx->pks->cert_files[0]))) { + SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dhparams); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Custom DH parameters (%d bits) for %s loaded from %s", + BN_num_bits(dhparams->p), vhost_id, + mctx->pks->cert_files[0]); + } + +#ifndef OPENSSL_NO_EC + /* + * Similarly, try to read the ECDH curve name from SSLCertificateFile... + */ + if ((mctx->pks->cert_files[0] != NULL) && + (ecparams = ssl_ec_GetParamFromFile(mctx->pks->cert_files[0])) && + (nid = EC_GROUP_get_curve_name(ecparams)) && + (eckey = EC_KEY_new_by_curve_name(nid))) { + SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "ECDH curve %s for %s specified in %s", + OBJ_nid2sn(nid), vhost_id, mctx->pks->cert_files[0]); + } +#endif } static void ssl_init_proxy_certs(server_rec *s, --- apache2-2.2.22.orig/modules/ssl/ssl_private.h +++ apache2-2.2.22/modules/ssl/ssl_private.h @@ -705,6 +705,9 @@ void ssl_pphrase_Handle(server_r /** Diffie-Hellman Parameter Support */ DH *ssl_dh_GetTmpParam(int); DH *ssl_dh_GetParamFromFile(char *); +#ifndef OPENSSL_NO_EC +EC_GROUP *ssl_ec_GetParamFromFile(const char *); +#endif unsigned char *ssl_asn1_table_set(apr_hash_t *table, const char *key, --- apache2-2.2.22.orig/modules/ssl/ssl_util_ssl.c +++ apache2-2.2.22/modules/ssl/ssl_util_ssl.c @@ -451,6 +451,26 @@ BOOL SSL_X509_INFO_load_path(apr_pool_t /* _________________________________________________________________ ** +** Custom (EC)DH parameter support +** _________________________________________________________________ +*/ + +#ifndef OPENSSL_NO_EC +EC_GROUP *ssl_ec_GetParamFromFile(const char *file) +{ + EC_GROUP *group = NULL; + BIO *bio; + + if ((bio = BIO_new_file(file, "r")) == NULL) + return NULL; + group = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); + BIO_free(bio); + return (group); +} +#endif + +/* _________________________________________________________________ +** ** Extra Server Certificate Chain Support ** _________________________________________________________________ */ --- apache2-2.2.22.orig/docs/manual/mod/mod_ssl.html.en +++ apache2-2.2.22/docs/manual/mod/mod_ssl.html.en @@ -388,12 +388,19 @@ SSLCertificateChainFile /usr/local/apach <tr><th><a href="directive-dict.html#Module">Module:</a></th><td>mod_ssl</td></tr> </table> <p> -This directive points to the PEM-encoded Certificate file for the server and -optionally also to the corresponding RSA or DSA Private Key file for it -(contained in the same file). If the contained Private Key is encrypted the -Pass Phrase dialog is forced at startup time. This directive can be used up to -two times (referencing different filenames) when both a RSA and a DSA based -server certificate is used in parallel.</p> +This directive points to the file with the PEM-encoded certificate, +optionally also the corresponding private key, and - beginning with +version 2.5.0-dev as of 2013-09-29 - DH parameters and/or an EC curve name +for ephemeral keys (as generated by <code>openssl dhparam</code> +and <code>openssl ecparam</code>, respectively). If the private key +is encrypted, the pass phrase dialog is forced at startup time. +</p> +<p> +This directive can be used up to three times (referencing different filenames) +when both an RSA, a DSA, and an ECC based server certificate is used in +parallel. Note that DH and ECDH parameters are only read from the first +<directive>SSLCertificateFile</directive> directive.</p> + <div class="example"><h3>Example</h3><p><code> SSLCertificateFile /usr/local/apache2/conf/ssl.crt/server.crt </code></p></div>