d9f2e03
--- contrib/mod_tls.c
d9f2e03
+++ contrib/mod_tls.c
d9f2e03
@@ -461,7 +461,7 @@ static tls_sess_cache_t *tls_sess_cache
d9f2e03
 static SSL *ctrl_ssl = NULL;
d9f2e03
 static SSL_CTX *ssl_ctx = NULL;
d9f2e03
 static X509_STORE *tls_crl_store = NULL;
d9f2e03
-static DH *tls_tmp_dh = NULL;
d9f2e03
+static array_header *tls_tmp_dhs = NULL;
d9f2e03
 static RSA *tls_tmp_rsa = NULL;
d9f2e03
 
d9f2e03
 /* SSL/TLS support functions */
d2f47d9
@@ -1952,58 +1952,60 @@ static int tls_ctrl_renegotiate_cb(CALLB
d9f2e03
 #endif
d9f2e03
 
d9f2e03
 static DH *tls_dh_cb(SSL *ssl, int is_export, int keylength) {
d9f2e03
-  FILE *fp = NULL;
d9f2e03
-
d9f2e03
-  if (tls_tmp_dh) {
d9f2e03
-    return tls_tmp_dh;
d9f2e03
-  }
d9f2e03
+  DH *dh = NULL;
d9f2e03
 
d9f2e03
-  if (tls_dhparam_file) {
d9f2e03
-    fp = fopen(tls_dhparam_file, "r");
d9f2e03
-    if (fp) {
d9f2e03
-      tls_tmp_dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
d9f2e03
-      fclose(fp);
d9f2e03
+  if (tls_tmp_dhs != NULL &&
d9f2e03
+      tls_tmp_dhs->nelts > 0) {
d9f2e03
+    register unsigned int i;
d9f2e03
+    DH **dhs;
d9f2e03
 
d9f2e03
-      if (tls_tmp_dh) {
d9f2e03
-        return tls_tmp_dh;
d9f2e03
+    dhs = tls_tmp_dhs->elts;
d9f2e03
+    for (i = 0; i < tls_tmp_dhs->nelts; i++) {
d9f2e03
+      /* Note: the keylength argument is in BITS, but DH_size() returns
d9f2e03
+       * the number of BYTES.
d9f2e03
+       */
d9f2e03
+      if (DH_size(dhs[i]) == (keylength / 8)) {
d9f2e03
+        return dhs[i];
d9f2e03
       }
d9f2e03
-
d9f2e03
-    } else {
d9f2e03
-      pr_log_debug(DEBUG3, MOD_TLS_VERSION
d9f2e03
-        ": unable to open TLSDHParamFile '%s': %s", tls_dhparam_file,
d9f2e03
-          strerror(errno));
d9f2e03
     }
d9f2e03
   }
d9f2e03
 
d9f2e03
   switch (keylength) {
d9f2e03
     case 512:
d9f2e03
-      tls_tmp_dh = get_dh512();
d9f2e03
+      dh = get_dh512();
d9f2e03
       break;
d9f2e03
 
d9f2e03
     case 768:
d9f2e03
-      tls_tmp_dh = get_dh768();
d9f2e03
+      dh = get_dh768();
d9f2e03
       break;
d9f2e03
 
d9f2e03
      case 1024:
d9f2e03
-       tls_tmp_dh = get_dh1024();
d9f2e03
+       dh = get_dh1024();
d9f2e03
        break;
d9f2e03
 
d9f2e03
      case 1536:
d9f2e03
-       tls_tmp_dh = get_dh1536();
d9f2e03
+       dh = get_dh1536();
d9f2e03
        break;
d9f2e03
 
d9f2e03
      case 2048:
d9f2e03
-       tls_tmp_dh = get_dh2048();
d9f2e03
+       dh = get_dh2048();
d9f2e03
        break;
d9f2e03
 
d9f2e03
      default:
d9f2e03
        tls_log("unsupported DH key length %d requested, returning 1024 bits",
d9f2e03
          keylength);
d9f2e03
-       tls_tmp_dh = get_dh1024();
d9f2e03
+       dh = get_dh1024();
d9f2e03
        break;
d9f2e03
   }
d9f2e03
 
d9f2e03
-  return tls_tmp_dh;
d9f2e03
+  /* Add this DH to the list, so that it can be freed properly later. */
d2f47d9
+  if (tls_tmp_dhs == NULL) {
d2f47d9
+    tls_tmp_dhs = make_array(session.pool, 1, sizeof(DH *));
d2f47d9
+  }
d2f47d9
+
d9f2e03
+  *((DH **) push_array(tls_tmp_dhs)) = dh;
d9f2e03
+
d9f2e03
+  return dh;
d9f2e03
 }
d9f2e03
 
d9f2e03
 /* Post 0.9.7a, RSA blinding is turned on by default, so there is no need to
d2f47d9
@@ -3018,9 +3020,16 @@ static void tls_cleanup(int flags) {
d9f2e03
     ssl_ctx = NULL;
d9f2e03
   }
d9f2e03
 
d9f2e03
-  if (tls_tmp_dh) {
d9f2e03
-    DH_free(tls_tmp_dh);
d9f2e03
-    tls_tmp_dh = NULL;
d9f2e03
+  if (tls_tmp_dhs) {
d9f2e03
+    register unsigned int i;
d9f2e03
+    DH **dhs;
d9f2e03
+
d9f2e03
+    dhs = tls_tmp_dhs->elts;
d9f2e03
+    for (i = 0; i < tls_tmp_dhs->nelts; i++) {
d9f2e03
+      DH_free(dhs[i]);
d9f2e03
+    }
d9f2e03
+
d9f2e03
+    tls_tmp_dhs = NULL;
d9f2e03
   }
d9f2e03
 
d9f2e03
   if (tls_tmp_rsa) {
d2f47d9
@@ -7320,6 +7329,38 @@ static int tls_sess_init(void) {
d9f2e03
   tls_crl_path = get_param_ptr(main_server->conf, "TLSCARevocationPath", FALSE);
d9f2e03
 
d9f2e03
   tls_dhparam_file = get_param_ptr(main_server->conf, "TLSDHParamFile", FALSE);
d9f2e03
+  if (tls_dhparam_file != NULL) {
d9f2e03
+    FILE *fp;
d9f2e03
+    int xerrno;
d9f2e03
+
d9f2e03
+    /* Load the DH params from the file. */
d9f2e03
+    PRIVS_ROOT
d9f2e03
+    fp = fopen(tls_dhparam_file, "r");
d9f2e03
+    xerrno = errno;
d9f2e03
+    PRIVS_RELINQUISH
d9f2e03
+
d9f2e03
+    if (fp != NULL) {
d9f2e03
+      DH *dh;
d9f2e03
+
d9f2e03
+      dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
d9f2e03
+      if (dh != NULL) {
d9f2e03
+        tls_tmp_dhs = make_array(session.pool, 1, sizeof(DH *));
d9f2e03
+      }
d9f2e03
+
d9f2e03
+      while (dh != NULL) {
d9f2e03
+        pr_signals_handle();
d9f2e03
+        *((DH **) push_array(tls_tmp_dhs)) = dh;
d9f2e03
+        dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
d9f2e03
+      }
d9f2e03
+
d9f2e03
+      fclose(fp);
d9f2e03
+
d9f2e03
+    } else {
d9f2e03
+      pr_log_debug(DEBUG3, MOD_TLS_VERSION
d9f2e03
+        ": unable to open TLSDHParamFile '%s': %s", tls_dhparam_file,
d9f2e03
+          strerror(xerrno));
d9f2e03
+    }
d9f2e03
+  }
d9f2e03
 
d9f2e03
   tls_dsa_cert_file = get_param_ptr(main_server->conf, "TLSDSACertificateFile",
d9f2e03
     FALSE);