This grew out of working on a proof of concept for
https://issues.apache.org/bugzilla/show_bug.cgi?id=49559 ("Patch to add
user-specified Diffie-Hellman parameters"). I would appreciate to get
more feedback on the changes proposed with the two attached patches...
which is the reason I'm taking the thing to the list.

I realized that there's quite some cruft in mod_ssl's ssl_engine_init.c
for dealing with ephemeral keys (the MODSSL_TMP_KEY_* macros and their
ssl_tmp_key_init_* friends). AFAICT, the primary reason for the whole
pTmpKeys dance with SSLModConfigRec at startup was due to the need of
pre-generating ephemeral RSA keys (as RSA key generation is an expensive
operation).

Ephemeral RSA, however, is basically a dead thing: specifically, it was
used to weaken the security strength at a time when there were US
export restrictions on what was considered "strong" crypto (more than
512 bits for key exchange in the 1990s). These restrictions were lifted
many, many years ago - in early 2000, to be precise [1].

I can't think of any good reason to still support export-grade ciphers
in 2013 - and if there's a consensus on this, I propose to get rid of
ssl_callback_TmpRSA etc. completely (see also [2] for more OpenSSL
specific background).

For DHE/ECDHE, there's no need to pre-generate keys at startup. In both
cases, what is needed are pre-generated *parameters* (from which OpenSSL
generates the keys on demand for every new SSL connection, which is a
cheap operation, see also [3] and the SSL_OP_SINGLE_DH_USE which mod_ssl
unconditionally sets).

In sum, I'm thinking of a two-step approach, as demonstrated by the
two attached patches (which can be applied to either trunk or 2.4.x). I
would be interested in getting feedback on the following points, in
particular:

- Does anyone object to dropping ephemeral RSA key support (and
unconditionally disabling export ciphers), at least for 2.4.x? If so,
for what reason?

- For the newly-added 2048-bit DH parameters, are there preferences to
use another value? (Right now, I took the parameter originally proposed
for SKIP - a pre-IKE proposal for IPSec key exchange from 1995. See the
comment in ssl_engine_dh.c patch for other potential candidates.)

- Are people fine with auto-increasing the DH parameter size to 2048
bits (for certs with RSA or DSA keys of at least 2048 bits)? This will
have some negative effects on interop, most likely, but sysadmins could
configure custom DH parameters (to downgrade to 1024 bits) as a
workaround in this case.

Thanks for sharing your thoughts. Reviews/testing of the patches are
also very welcome, of course.

Kaspar


[1] http://epic.org/crypto/export_controls/regs_1_00.html

[2] http://www.openssl.org/docs/ssl/SSL_CTX_set_tmp_rsa_callback.html#NOTES

[3] http://www.openssl.org/docs/ssl/SSL_CTX_set_tmp_dh_callback.html#NOTES
Streamline/improve ephemeral key handling, part 1:

- drop support for ephemeral RSA keys (only allowed for export ciphers)
  and unconditionally disable EXP ciphers

- do not configure per-SSL tmp_*_callbacks (use the SSL_CTX instead)

- drop pTmpKeys from the per-process SSLModConfigRec, and remove
  the temp key generation at startup (not needed for DHE/ECDHE)

- set default curve for ECDHE at startup (and also configure
  SSL_OP_SINGLE_ECDH_USE, which was previously left out)

Index: ssl_private.h
===================================================================
--- ssl_private.h       (revision 1509097)
+++ ssl_private.h       (working copy)
@@ -534,7 +534,6 @@ typedef struct {
     apr_global_mutex_t   *pMutex;
     apr_array_header_t   *aRandSeed;
     apr_hash_t     *tVHostKeys;
-    void           *pTmpKeys[SSL_TMP_KEY_MAX];
 
     /* Two hash tables of pointers to ssl_asn1_t structures.  The
      * structures are used to store certificates and private keys
@@ -823,11 +822,7 @@ extern const authz_provider ssl_authz_provider_req
 extern const authz_provider ssl_authz_provider_verify_client;
 
 /**  OpenSSL callbacks */
-RSA         *ssl_callback_TmpRSA(SSL *, int, int);
 DH          *ssl_callback_TmpDH(SSL *, int, int);
-#ifndef OPENSSL_NO_EC
-EC_KEY      *ssl_callback_TmpECDH(SSL *, int, int);
-#endif
 int          ssl_callback_SSLVerify(int, X509_STORE_CTX *);
 int          ssl_callback_SSLVerify_CRL(int, X509_STORE_CTX *, conn_rec *);
 int          ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
Index: mod_ssl.c
===================================================================
--- mod_ssl.c   (revision 1509097)
+++ mod_ssl.c   (working copy)
@@ -471,15 +471,6 @@ int ssl_init_ssl_connection(conn_rec *c, request_r
 
     sslconn->ssl = ssl;
 
-    /*
-     *  Configure callbacks for SSL connection
-     */
-    SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA);
-    SSL_set_tmp_dh_callback(ssl,  ssl_callback_TmpDH);
-#ifndef OPENSSL_NO_EC
-    SSL_set_tmp_ecdh_callback(ssl, ssl_callback_TmpECDH);
-#endif
-
     SSL_set_verify_result(ssl, X509_V_OK);
 
     ssl_io_filter_init(c, r, ssl);
Index: ssl_engine_init.c
===================================================================
--- ssl_engine_init.c   (revision 1509097)
+++ ssl_engine_init.c   (working copy)
@@ -56,181 +56,7 @@ static void ssl_add_version_components(apr_pool_t
                  modver, AP_SERVER_BASEVERSION, incver);
 }
 
-
 /*
- * Handle the Temporary RSA Keys and DH Params
- */
-
-#define MODSSL_TMP_KEY_FREE(mc, type, idx) \
-    if (mc->pTmpKeys[idx]) { \
-        type##_free((type *)mc->pTmpKeys[idx]); \
-        mc->pTmpKeys[idx] = NULL; \
-    }
-
-#define MODSSL_TMP_KEYS_FREE(mc, type) \
-    MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_512); \
-    MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_1024)
-
-static void ssl_tmp_keys_free(server_rec *s)
-{
-    SSLModConfigRec *mc = myModConfig(s);
-
-    MODSSL_TMP_KEYS_FREE(mc, RSA);
-    MODSSL_TMP_KEYS_FREE(mc, DH);
-#ifndef OPENSSL_NO_EC
-    MODSSL_TMP_KEY_FREE(mc, EC_KEY, SSL_TMP_KEY_EC_256);
-#endif
-}
-
-static int ssl_tmp_key_init_rsa(server_rec *s,
-                                int bits, int idx)
-{
-    SSLModConfigRec *mc = myModConfig(s);
-
-#ifdef HAVE_FIPS
-
-    if (FIPS_mode() && bits < 1024) {
-        mc->pTmpKeys[idx] = NULL;
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01877)
-                     "Init: Skipping generating temporary "
-                     "%d bit RSA private key in FIPS mode", bits);
-        return OK;
-    }
-
-#endif
-#ifdef HAVE_GENERATE_EX
-    {
-        RSA *tkey;
-        BIGNUM *bn_f4;
-        if (!(tkey = RSA_new())
-          || !(bn_f4 = BN_new())
-          || !BN_set_word(bn_f4, RSA_F4)
-          || !RSA_generate_key_ex(tkey, bits, bn_f4, NULL))
-        {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01878)
-                         "Init: Failed to generate temporary "
-                         "%d bit RSA private key", bits);
-            ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
-            return !OK;
-        }
-        BN_free(bn_f4);
-        mc->pTmpKeys[idx] = tkey;
-    }
-#else
-    if (!(mc->pTmpKeys[idx] =
-          RSA_generate_key(bits, RSA_F4, NULL, NULL)))
-    {
-        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01879)
-                     "Init: Failed to generate temporary "
-                     "%d bit RSA private key", bits);
-        ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
-        return !OK;
-    }
-#endif
-
-    return OK;
-}
-
-static int ssl_tmp_key_init_dh(server_rec *s,
-                               int bits, int idx)
-{
-    SSLModConfigRec *mc = myModConfig(s);
-
-#ifdef HAVE_FIPS
-
-    if (FIPS_mode() && bits < 1024) {
-        mc->pTmpKeys[idx] = NULL;
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01880)
-                     "Init: Skipping generating temporary "
-                     "%d bit DH parameters in FIPS mode", bits);
-        return OK;
-    }
-
-#endif
-
-    if (!(mc->pTmpKeys[idx] =
-          ssl_dh_GetTmpParam(bits)))
-    {
-        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01881)
-                     "Init: Failed to generate temporary "
-                     "%d bit DH parameters", bits);
-        return !OK;
-    }
-
-    return OK;
-}
-
-#ifndef OPENSSL_NO_EC
-static int ssl_tmp_key_init_ec(server_rec *s,
-                               int bits, int idx)
-{
-    SSLModConfigRec *mc = myModConfig(s);
-    EC_KEY *ecdh = NULL;
-
-    /* XXX: Are there any FIPS constraints we should enforce? */
-
-    if (bits != 256) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02298)
-                     "Init: Failed to generate temporary "
-                     "%d bit EC parameters, only 256 bits supported", bits);
-        return !OK;
-    }
-
-    if ((ecdh = EC_KEY_new()) == NULL ||
-        EC_KEY_set_group(ecdh, 
EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) != 1)
-    {
-        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02299)
-                     "Init: Failed to generate temporary "
-                     "%d bit EC parameters", bits);
-        return !OK;
-    }
-
-    mc->pTmpKeys[idx] = ecdh;
-    return OK;
-}
-
-#define MODSSL_TMP_KEY_INIT_EC(s, bits) \
-    ssl_tmp_key_init_ec(s, bits, SSL_TMP_KEY_EC_##bits)
-
-#endif
-
-#define MODSSL_TMP_KEY_INIT_RSA(s, bits) \
-    ssl_tmp_key_init_rsa(s, bits, SSL_TMP_KEY_RSA_##bits)
-
-#define MODSSL_TMP_KEY_INIT_DH(s, bits) \
-    ssl_tmp_key_init_dh(s, bits, SSL_TMP_KEY_DH_##bits)
-
-static int ssl_tmp_keys_init(server_rec *s)
-{
-    ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
-                 "Init: Generating temporary RSA private keys (512/1024 
bits)");
-
-    if (MODSSL_TMP_KEY_INIT_RSA(s, 512) ||
-        MODSSL_TMP_KEY_INIT_RSA(s, 1024)) {
-        return !OK;
-    }
-
-    ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
-                 "Init: Generating temporary DH parameters (512/1024 bits)");
-
-    if (MODSSL_TMP_KEY_INIT_DH(s, 512) ||
-        MODSSL_TMP_KEY_INIT_DH(s, 1024)) {
-        return !OK;
-    }
-
-#ifndef OPENSSL_NO_EC
-    ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
-                 "Init: Generating temporary EC parameters (256 bits)");
-
-    if (MODSSL_TMP_KEY_INIT_EC(s, 256)) {
-        return !OK;
-    }
-#endif
-
-    return OK;
-}
-
-/*
  *  Per-module initialization
  */
 int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
@@ -367,10 +193,6 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plo
      */
     ssl_pphrase_Handle(base_server, ptemp);
 
-    if (ssl_tmp_keys_init(base_server)) {
-        return !OK;
-    }
-
     /*
      * initialize the mutex handling
      */
@@ -678,6 +500,9 @@ static void ssl_init_ctx_protocol(server_rec *s,
      * Configure additional context ingredients
      */
     SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
+#ifndef OPENSSL_NO_EC
+    SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
+#endif
 
 #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
     /*
@@ -718,11 +543,7 @@ static void ssl_init_ctx_callbacks(server_rec *s,
 {
     SSL_CTX *ctx = mctx->ssl_ctx;
 
-    SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA);
     SSL_CTX_set_tmp_dh_callback(ctx,  ssl_callback_TmpDH);
-#ifndef OPENSSL_NO_EC
-    SSL_CTX_set_tmp_ecdh_callback(ctx,ssl_callback_TmpECDH);
-#endif
 
     SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
 }
@@ -818,14 +639,15 @@ static void ssl_init_ctx_cipher_suite(server_rec *
                                       modssl_ctx_t *mctx)
 {
     SSL_CTX *ctx = mctx->ssl_ctx;
-    const char *suite = mctx->auth.cipher_suite;
+    const char *suite;
 
     /*
-     *  Configure SSL Cipher Suite
+     *  Configure SSL Cipher Suite. Always disable NULL and export ciphers,
+     *  no matter what SSLCipherSuite directive is put into the config file.
      */
-    if (!suite) {
-        return;
-    }
+    suite = apr_pstrcat(ptemp, "!aNULL:!eNULL:!EXP:", mctx->auth.cipher_suite ?
+                        mctx->auth.cipher_suite : SSL_DEFAULT_CIPHER_LIST,
+                        NULL);
 
     ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
                  "Configuring permitted SSL ciphers [%s]",
@@ -1209,6 +1031,12 @@ static void ssl_init_server_certs(server_rec *s,
                 "Oops, no " KEYTYPES " server private key found?!");
         ssl_die(s);
     }
+
+#ifndef OPENSSL_NO_EC
+    /* Enable ECDHE by configuring a default curve */
+    SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx,
+                         EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+#endif
 }
 
 #ifdef HAVE_TLS_SESSION_TICKETS
@@ -1745,11 +1573,6 @@ apr_status_t ssl_init_ModuleKill(void *data)
     ssl_scache_kill(base_server);
 
     /*
-     * Destroy the temporary keys and params
-     */
-    ssl_tmp_keys_free(base_server);
-
-    /*
      * Free the non-pool allocated structures
      * in the per-server configurations
      */
Index: ssl_engine_config.c
===================================================================
--- ssl_engine_config.c (revision 1509097)
+++ ssl_engine_config.c (working copy)
@@ -75,8 +75,6 @@ SSLModConfigRec *ssl_config_global_create(server_r
     mc->stapling_mutex         = NULL;
 #endif
 
-    memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys));
-
     apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY,
                           apr_pool_cleanup_null,
                           pool);
Index: ssl_engine_kernel.c
===================================================================
--- ssl_engine_kernel.c (revision 1509097)
+++ ssl_engine_kernel.c (working copy)
@@ -1287,118 +1287,18 @@ const authz_provider ssl_authz_provider_verify_cli
 */
 
 /*
- * Handle out temporary RSA private keys on demand
- *
- * The background of this as the TLSv1 standard explains it:
- *
- * | D.1. Temporary RSA keys
- * |
- * |    US Export restrictions limit RSA keys used for encryption to 512
- * |    bits, but do not place any limit on lengths of RSA keys used for
- * |    signing operations. Certificates often need to be larger than 512
- * |    bits, since 512-bit RSA keys are not secure enough for high-value
- * |    transactions or for applications requiring long-term security. Some
- * |    certificates are also designated signing-only, in which case they
- * |    cannot be used for key exchange.
- * |
- * |    When the public key in the certificate cannot be used for encryption,
- * |    the server signs a temporary RSA key, which is then exchanged. In
- * |    exportable applications, the temporary RSA key should be the maximum
- * |    allowable length (i.e., 512 bits). Because 512-bit RSA keys are
- * |    relatively insecure, they should be changed often. For typical
- * |    electronic commerce applications, it is suggested that keys be
- * |    changed daily or every 500 transactions, and more often if possible.
- * |    Note that while it is acceptable to use the same temporary key for
- * |    multiple transactions, it must be signed each time it is used.
- * |
- * |    RSA key generation is a time-consuming process. In many cases, a
- * |    low-priority process can be assigned the task of key generation.
- * |    Whenever a new key is completed, the existing temporary key can be
- * |    replaced with the new one.
- *
- * XXX: base on comment above, if thread support is enabled,
- * we should spawn a low-priority thread to generate new keys
- * on the fly.
- *
- * So we generated 512 and 1024 bit temporary keys on startup
- * which we now just hand out on demand....
- */
-
-RSA *ssl_callback_TmpRSA(SSL *ssl, int export, int keylen)
-{
-    conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
-    SSLModConfigRec *mc = myModConfigFromConn(c);
-    int idx;
-
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
-                  "handing out temporary %d bit RSA key", keylen);
-
-    /* doesn't matter if export flag is on,
-     * we won't be asked for keylen > 512 in that case.
-     * if we are asked for a keylen > 1024, it is too expensive
-     * to generate on the fly.
-     * XXX: any reason not to generate 2048 bit keys at startup?
-     */
-
-    switch (keylen) {
-      case 512:
-        idx = SSL_TMP_KEY_RSA_512;
-        break;
-
-      case 1024:
-      default:
-        idx = SSL_TMP_KEY_RSA_1024;
-    }
-
-    return (RSA *)mc->pTmpKeys[idx];
-}
-
-/*
  * Hand out the already generated DH parameters...
  */
 DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen)
 {
     conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
-    SSLModConfigRec *mc = myModConfigFromConn(c);
-    int idx;
 
     ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
-                  "handing out temporary %d bit DH key", keylen);
+                  "handing out parameters for temporary %d bit DH key", 
keylen);
 
-    switch (keylen) {
-      case 512:
-        idx = SSL_TMP_KEY_DH_512;
-        break;
-
-      case 1024:
-      default:
-        idx = SSL_TMP_KEY_DH_1024;
-    }
-
-    return (DH *)mc->pTmpKeys[idx];
+    return ssl_dh_GetTmpParam(keylen);
 }
 
-#ifndef OPENSSL_NO_EC
-EC_KEY *ssl_callback_TmpECDH(SSL *ssl, int export, int keylen)
-{
-    conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
-    SSLModConfigRec *mc = myModConfigFromConn(c);
-    int idx;
-
-    /* XXX Uses 256-bit key for now. TODO: support other sizes. */
-    ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
-                  "handing out temporary 256 bit ECC key");
-
-    switch (keylen) {
-      case 256:
-      default:
-        idx = SSL_TMP_KEY_EC_256;
-    }
-
-    return (EC_KEY *)mc->pTmpKeys[idx];
-}
-#endif
-
 /*
  * This OpenSSL callback function is called when OpenSSL
  * does client authentication and verifies the certificate chain.
Streamline/improve ephemeral key handling, part 2:

- add well-defined 2048-bit DH parameters, and use them
  if a certificate with an RSA or DSA key with 2048 bits or more
  is configured

- allow to configure custom DHE or ECDHE parameters via the
  SSLCertificateFile directive

- move ssl_dh_GetParamFromFile() from ssl_engine_dh.c to
  ssl_util_ssl.c, and add ssl_ec_GetParamFromFile()

Index: ssl_private.h
===================================================================
--- ssl_private.h       (revision 1509097)
+++ ssl_private.h       (working copy)
@@ -902,7 +902,10 @@ void         ssl_pphrase_Handle(server_rec *, apr_
 
 /**  Diffie-Hellman Parameter Support  */
 DH           *ssl_dh_GetTmpParam(int);
-DH           *ssl_dh_GetParamFromFile(char *);
+DH           *ssl_dh_GetParamFromFile(const 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,
Index: ssl_engine_dh.c
===================================================================
--- ssl_engine_dh.c     (revision 1509097)
+++ ssl_engine_dh.c     (working copy)
@@ -122,31 +122,73 @@ static DH *get_dh1024(void)
 
 /* ----END GENERATED SECTION---------- */
 
+/*
+ * For 2048 bits, hard code parameters whose prime generation is publicly
+ * documented: http://tools.ietf.org/html/draft-ietf-ipsec-skip-04
+ * [XXX other potential choices, not necessarily meeting that requirement:
+ *  RFC 3526 (section 3), RFC 5114 (sections 2.2/2.3)... the latter
+ *  if you're fine with NIST-suggested parameters]
+ */
+
+static unsigned char dh2048_p[] = {
+    0xF6, 0x42, 0x57, 0xB7, 0x08, 0x7F, 0x08, 0x17, 0x72, 0xA2, 0xBA, 0xD6, 
+    0xA9, 0x42, 0xF3, 0x05, 0xE8, 0xF9, 0x53, 0x11, 0x39, 0x4F, 0xB6, 0xF1, 
+    0x6E, 0xB9, 0x4B, 0x38, 0x20, 0xDA, 0x01, 0xA7, 0x56, 0xA3, 0x14, 0xE9, 
+    0x8F, 0x40, 0x55, 0xF3, 0xD0, 0x07, 0xC6, 0xCB, 0x43, 0xA9, 0x94, 0xAD, 
+    0xF7, 0x4C, 0x64, 0x86, 0x49, 0xF8, 0x0C, 0x83, 0xBD, 0x65, 0xE9, 0x17, 
+    0xD4, 0xA1, 0xD3, 0x50, 0xF8, 0xF5, 0x59, 0x5F, 0xDC, 0x76, 0x52, 0x4F, 
+    0x3D, 0x3D, 0x8D, 0xDB, 0xCE, 0x99, 0xE1, 0x57, 0x92, 0x59, 0xCD, 0xFD, 
+    0xB8, 0xAE, 0x74, 0x4F, 0xC5, 0xFC, 0x76, 0xBC, 0x83, 0xC5, 0x47, 0x30, 
+    0x61, 0xCE, 0x7C, 0xC9, 0x66, 0xFF, 0x15, 0xF9, 0xBB, 0xFD, 0x91, 0x5E, 
+    0xC7, 0x01, 0xAA, 0xD3, 0x5B, 0x9E, 0x8D, 0xA0, 0xA5, 0x72, 0x3A, 0xD4, 
+    0x1A, 0xF0, 0xBF, 0x46, 0x00, 0x58, 0x2B, 0xE5, 0xF4, 0x88, 0xFD, 0x58, 
+    0x4E, 0x49, 0xDB, 0xCD, 0x20, 0xB4, 0x9D, 0xE4, 0x91, 0x07, 0x36, 0x6B, 
+    0x33, 0x6C, 0x38, 0x0D, 0x45, 0x1D, 0x0F, 0x7C, 0x88, 0xB3, 0x1C, 0x7C, 
+    0x5B, 0x2D, 0x8E, 0xF6, 0xF3, 0xC9, 0x23, 0xC0, 0x43, 0xF0, 0xA5, 0x5B, 
+    0x18, 0x8D, 0x8E, 0xBB, 0x55, 0x8C, 0xB8, 0x5D, 0x38, 0xD3, 0x34, 0xFD, 
+    0x7C, 0x17, 0x57, 0x43, 0xA3, 0x1D, 0x18, 0x6C, 0xDE, 0x33, 0x21, 0x2C, 
+    0xB5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40, 0x18, 0x11, 0x8D, 0x7C, 
+    0x84, 0xA7, 0x0A, 0x72, 0xD6, 0x86, 0xC4, 0x03, 0x19, 0xC8, 0x07, 0x29, 
+    0x7A, 0xCA, 0x95, 0x0C, 0xD9, 0x96, 0x9F, 0xAB, 0xD0, 0x0A, 0x50, 0x9B, 
+    0x02, 0x46, 0xD3, 0x08, 0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C, 
+    0xBD, 0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB, 0xA2, 0x5E, 0xC3, 0x55, 
+    0xE9, 0x32, 0x0B, 0x3B, 
+    };
+static unsigned char dh2048_g[] = {
+        0x02,
+};
+
+static DH *get_dh2048(void)
+{
+    DH *dh;
+
+    if (!(dh = DH_new())) {
+        return NULL;
+    }
+
+    dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
+    dh->g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
+    if (!(dh->p && dh->g)) {
+        DH_free(dh);
+        return NULL;
+    }
+
+    return dh;
+}
+
 DH *ssl_dh_GetTmpParam(int nKeyLen)
 {
     DH *dh;
 
     if (nKeyLen == 512)
         dh = get_dh512();
-    else if (nKeyLen == 1024)
-        dh = get_dh1024();
+    else if (nKeyLen >= 2048)
+        dh = get_dh2048();
     else
         dh = get_dh1024();
     return dh;
 }
 
-DH *ssl_dh_GetParamFromFile(char *file)
-{
-    DH *dh = NULL;
-    BIO *bio;
-
-    if ((bio = BIO_new_file(file, "r")) == NULL)
-        return NULL;
-    dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
-    BIO_free(bio);
-    return (dh);
-}
-
 /*
 =cut
 ##
Index: ssl_engine_init.c
===================================================================
--- ssl_engine_init.c   (revision 1509097)
+++ ssl_engine_init.c   (working copy)
@@ -980,10 +980,14 @@ static void ssl_init_server_certs(server_rec *s,
     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
@@ -1031,10 +1035,38 @@ static void ssl_init_server_certs(server_rec *s,
         ssl_die(s);
     }
 
+    /*
+     * Try to read DHE 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, APLOGNO()
+                     "DHE parameters (%d bits) for %s configured from %s",
+                     BN_num_bits(dhparams->p), vhost_id,
+                     mctx->pks->cert_files[0]);
+    }
+
 #ifndef OPENSSL_NO_EC
-    /* Enable ECDHE by configuring a default curve */
-    SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx,
-                         EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+    /*
+     * Similarly, try to read the ECDHE 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, APLOGNO()
+                     "ECDHE curve (%s) for %s configured from %s",
+                     OBJ_nid2sn(nid), vhost_id, mctx->pks->cert_files[0]);
+    }
+    /*
+     * ...otherwise, configure a default curve (required to enable ECDHE)
+     */
+    else {
+        SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx,
+                             EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+    }
 #endif
 }
 
Index: ssl_util_ssl.c
===================================================================
--- ssl_util_ssl.c      (revision 1509097)
+++ ssl_util_ssl.c      (working copy)
@@ -483,6 +483,38 @@ BOOL SSL_X509_INFO_load_path(apr_pool_t *ptemp,
 
 /*  _________________________________________________________________
 **
+**  Custom (EC)DH parameter support
+**  _________________________________________________________________
+*/
+
+DH *ssl_dh_GetParamFromFile(const char *file)
+{
+    DH *dh = NULL;
+    BIO *bio;
+
+    if ((bio = BIO_new_file(file, "r")) == NULL)
+        return NULL;
+    dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+    BIO_free(bio);
+    return (dh);
+}
+
+#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
 **  _________________________________________________________________
 */
Index: ssl_engine_kernel.c
===================================================================
--- ssl_engine_kernel.c (revision 1509097)
+++ ssl_engine_kernel.c (working copy)
@@ -1292,7 +1292,25 @@ const authz_provider ssl_authz_provider_verify_cli
 DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen)
 {
     conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
+    EVP_PKEY *pkey = SSL_get_privatekey(ssl);
+    int type;
 
+    /*
+     * OpenSSL will call us with either keylen == 512 or keylen == 1024
+     * (see the definition of SSL_EXPORT_PKEYLENGTH in ssl_locl.h).
+     * Adjust/increase the DH parameter length if we can determine that
+     * the RSA/DSA private key used for the current connection is 2048 bits
+     * or more.
+     * XXX Note: This may cause interoperability issues with implementations
+     * which limit their DH support to 1024 bit - e.g. Java 7 and earlier, cf.
+     * 
http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/tip/src/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java
+     */
+    if (pkey && (type = EVP_PKEY_type(pkey->type)) &&
+        ((type == EVP_PKEY_RSA) || (type == EVP_PKEY_DSA)) &&
+        (EVP_PKEY_bits(pkey) >= 2048)) {
+        keylen = 2048;
+    }
+
     ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
                   "handing out parameters for temporary %d bit DH key", 
keylen);
 

Reply via email to