I've seen this problem to be open quite long time, and I believe it occurs 
because exim tries to generate Diffie Hellman parameters on the fly when they 
don't exist. This situation may occur when the gnutls-params file is missing. 
I propose some solutions.

1. Return an error if the gnutls-params file does not exist. (sol1.patch)

2. Generate the parameters in a non-blocking way using /dev/urandom. 
(sol2.patch)

3. Read static parameters if the file does not exist.


I believe the third solution is the most elegant. Generating these parameters 
on the fly (sol2) even if /dev/urandom is used is time consuming and not 
really appropriate for a server. The idea is to have them pregenerated. 

Using static parameters (sol3) does not harm in any way.
If somebody wants different ones he can generate them.

So the 
--- tls-gnu.c.org	2007-10-21 23:51:28.000000000 +0300
+++ tls-gnu.c	2007-10-21 23:56:04.000000000 +0300
@@ -362,54 +362,7 @@
 case. */
 
 if (ret < 0)
-  {
-  uschar tempfilename[sizeof(filename) + 10];
-
-  DEBUG(D_tls) debug_printf("generating %d bit Diffie-Hellman key...\n",
-    DH_BITS);
-  ret = gnutls_dh_params_generate2(dh_params, DH_BITS);
-  if (ret < 0) return tls_error(US"D-H key generation", host, ret);
-
-  /* Write the parameters to a file in the spool directory so that we
-  can use them from other Exim processes. */
-
-  sprintf(CS tempfilename, "%s-%d", filename, (int)getpid());
-  fd = Uopen(tempfilename, O_WRONLY|O_CREAT, 0400);
-  if (fd < 0)
-    return tls_error(string_open_failed(errno, "%s for writing", filename),
-      host, 0);
-  (void)fchown(fd, exim_uid, exim_gid);   /* Probably not necessary */
-
-  /* export the parameters in a format that can be generated using GNUTLS'
-   * certtool or other programs.
-   *
-   * The commands for certtool are:
-   * $ certtool --generate-dh-params --bits 1024 > params
-   */
-
-  m.size = PARAM_SIZE;
-  m.data = malloc(m.size);
-  if (m.data == NULL)
-    return tls_error(US"memory allocation failed", host, 0);
-
-  m.size = PARAM_SIZE;
-  ret = gnutls_dh_params_export_pkcs3(dh_params, GNUTLS_X509_FMT_PEM, m.data,
-    &m.size);
-  if (ret < 0) return tls_error(US"DH params export", host, ret);
-
-  m.size = Ustrlen(m.data);
-  if (write(fd, m.data, m.size) != m.size || write(fd, "\n", 1) != 1)
-    return tls_error(US"TLS cache write failed", host, 0);
-
-  free(m.data);
-  (void)close(fd);
-
-  if (rename(CS tempfilename, CS filename) < 0)
-    return tls_error(string_sprintf("failed to rename %s as %s: %s",
-      tempfilename, filename, strerror(errno)), host, 0);
-
-  DEBUG(D_tls) debug_printf("wrote D-H parameters to file %s\n", filename);
-  }
+  return tls_error(US"DH parameters file \"%s\" was not found. It must be present to use TLS.", filename);
 
 DEBUG(D_tls) debug_printf("initialized D-H parameters\n");
 return OK;
--- tls-gnu.c.org	2007-10-21 23:51:28.000000000 +0300
+++ tls-gnu.c	2007-10-21 23:58:12.000000000 +0300
@@ -17,6 +17,7 @@
 
 /* Heading stuff for GnuTLS */
 
+#include <gcrypt.h>
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
 
@@ -444,6 +445,10 @@
 
 initialized = (host == NULL)? INITIALIZED_SERVER : INITIALIZED_CLIENT;
 
+/* To use /dev/urandom even for key generation
+ */
+gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
 rc = gnutls_global_init();
 if (rc < 0) return tls_error(US"tls-init", host, rc);
 
--- tls-gnu.c.org	2007-10-21 23:51:28.000000000 +0300
+++ tls-gnu.c	2007-10-22 00:10:00.000000000 +0300
@@ -279,6 +279,13 @@
 *            Setup up DH parameters              *
 *************************************************/
 
+const static char pkcs3[] = 
+"-----BEGIN DH PARAMETERS-----\n"
+"MIGGAoGA7q8Kua2zjdacM/gK+o/F6GByYYd1/zwLnqIxTJwlZXbWdN90luqB0zg7\n"
+"SBPWksbg4NXY4lC5i+SOSVwdYIna0V3H17RhVNa2zo70rWmxXUmCVZspe88YhcUp\n"
+"9WZmDlfsaO28PAVybMAv1Mv0l26qmv1ROP6DdkNbn8YdL8DrBuMCAQI=\n"
+"-----END DH PARAMETERS-----\n";
+
 /* Generating the D-H parameters may take a long time. They only need to
 be re-generated every so often, depending on security policy. What we do is to
 keep these parameters in a file in the spool directory. If the file does not
@@ -294,7 +301,6 @@
 
 Returns:     OK/DEFER/FAIL
 */
-
 static int
 init_dh(host_item *host)
 {
@@ -363,52 +369,10 @@
 
 if (ret < 0)
   {
-  uschar tempfilename[sizeof(filename) + 10];
-
-  DEBUG(D_tls) debug_printf("generating %d bit Diffie-Hellman key...\n",
-    DH_BITS);
-  ret = gnutls_dh_params_generate2(dh_params, DH_BITS);
-  if (ret < 0) return tls_error(US"D-H key generation", host, ret);
-
-  /* Write the parameters to a file in the spool directory so that we
-  can use them from other Exim processes. */
-
-  sprintf(CS tempfilename, "%s-%d", filename, (int)getpid());
-  fd = Uopen(tempfilename, O_WRONLY|O_CREAT, 0400);
-  if (fd < 0)
-    return tls_error(string_open_failed(errno, "%s for writing", filename),
-      host, 0);
-  (void)fchown(fd, exim_uid, exim_gid);   /* Probably not necessary */
-
-  /* export the parameters in a format that can be generated using GNUTLS'
-   * certtool or other programs.
-   *
-   * The commands for certtool are:
-   * $ certtool --generate-dh-params --bits 1024 > params
-   */
-
-  m.size = PARAM_SIZE;
-  m.data = malloc(m.size);
-  if (m.data == NULL)
-    return tls_error(US"memory allocation failed", host, 0);
+  gnutls_datum dparams = { pkcs3, sizeof (pkcs3) };
 
-  m.size = PARAM_SIZE;
-  ret = gnutls_dh_params_export_pkcs3(dh_params, GNUTLS_X509_FMT_PEM, m.data,
-    &m.size);
-  if (ret < 0) return tls_error(US"DH params export", host, ret);
-
-  m.size = Ustrlen(m.data);
-  if (write(fd, m.data, m.size) != m.size || write(fd, "\n", 1) != 1)
-    return tls_error(US"TLS cache write failed", host, 0);
-
-  free(m.data);
-  (void)close(fd);
-
-  if (rename(CS tempfilename, CS filename) < 0)
-    return tls_error(string_sprintf("failed to rename %s as %s: %s",
-      tempfilename, filename, strerror(errno)), host, 0);
-
-  DEBUG(D_tls) debug_printf("wrote D-H parameters to file %s\n", filename);
+  ret = gnutls_dh_params_import_pkcs3(dh_params, &dparams, GNUTLS_X509_FMT_PEM);
+  if (ret < 0) return tls_error(US"DH params import", host, ret);
   }
 
 DEBUG(D_tls) debug_printf("initialized D-H parameters\n");

Reply via email to