Index: doc/freediameter.conf.sample
===================================================================
--- doc/freediameter.conf.sample	(revision 513)
+++ doc/freediameter.conf.sample	(revision 578)
@@ -120,4 +120,11 @@
 # Default : 1024
 #TLS_DH_Bits = 1024;
+
+# Alternatively, you can specify a file to load the PKCS#3 encoded
+# DH parameters directly from. This accelerates the daemon start 
+# but is slightly less secure. If this file is provided, the
+# TLS_DH_Bits parameters has no effect.
+# Default : no default.
+#TLS_DH_File = "<file.PEM>";
 
 
Index: freeDiameter/config.c
===================================================================
--- freeDiameter/config.c	(revision 542)
+++ freeDiameter/config.c	(revision 578)
@@ -134,5 +134,8 @@
 	fd_log_debug("          - CRL .......... : %s\n", fd_g_config->cnf_sec_data.crl_file ?: "(none)");
 	fd_log_debug("          - Priority ..... : %s\n", fd_g_config->cnf_sec_data.prio_string ?: "(default: '" GNUTLS_DEFAULT_PRIORITY "')");
-	fd_log_debug("          - DH bits ...... : %d\n", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS);
+	if (fd_g_config->cnf_sec_data.dh_file)
+		fd_log_debug("          - DH file ...... : %s\n", fd_g_config->cnf_sec_data.dh_file);
+	else
+		fd_log_debug("          - DH bits ...... : %d\n", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS);
 	
 	fd_log_debug("  Origin-State-Id ........ : %u\n", fd_g_config->cnf_orstateid);
@@ -261,12 +264,4 @@
 				 { TRACE_DEBUG(INFO, "Error in priority string at position : %s", err_pos); return EINVAL; } );
 	}
-	if (! fd_g_config->cnf_sec_data.dh_bits) {
-		TRACE_DEBUG(INFO, "Generating Diffie-Hellman parameters of size %d (this takes a few seconds)... ", GNUTLS_DEFAULT_DHBITS);
-		CHECK_GNUTLS_DO( gnutls_dh_params_generate2( 
-					fd_g_config->cnf_sec_data.dh_cache,
-					GNUTLS_DEFAULT_DHBITS),
-				 { TRACE_DEBUG(INFO, "Error in DH bits value : %d", GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
-	}
-	
 	
 	/* Verify that our certificate is valid -- otherwise remote peers will reject it */
@@ -403,4 +398,54 @@
 	/* gnutls_certificate_set_verify_limits -- so far the default values are fine... */
 	
+	/* DH */
+	if (fd_g_config->cnf_sec_data.dh_file) {
+		gnutls_datum_t dhparams = { NULL, 0 };
+		size_t alloc = 0;
+		FILE *stream = fopen (fd_g_config->cnf_sec_data.dh_file, "rb");
+		if (!stream) {
+			int err = errno;
+			TRACE_DEBUG(INFO, "An error occurred while opening '%s': %s\n", fd_g_config->cnf_sec_data.dh_file, strerror(err));
+			return err; 
+		}
+		do {
+			uint8_t * realloced = NULL;
+			size_t read = 0;
+			
+			if (alloc < dhparams.size + BUFSIZ + 1) {
+				alloc += alloc / 2 + BUFSIZ + 1;
+				CHECK_MALLOC_DO( realloced = realloc(dhparams.data, alloc),
+					{
+						free(dhparams.data);
+						return ENOMEM;
+					} )
+				dhparams.data = realloced;
+			}
+			
+			read = fread( dhparams.data + dhparams.size, 1, alloc - dhparams.size - 1, stream );
+			dhparams.size += read;
+			
+			if (ferror(stream)) {
+				int err = errno;
+				TRACE_DEBUG(INFO, "An error occurred while reading '%s': %s\n", fd_g_config->cnf_sec_data.dh_file, strerror(err));
+				return err; 
+			}
+		} while (!feof(stream));
+		dhparams.data[dhparams.size] = '\0';
+		fclose(stream);
+		CHECK_GNUTLS_DO( gnutls_dh_params_import_pkcs3( 
+					fd_g_config->cnf_sec_data.dh_cache,
+					&dhparams,
+					GNUTLS_X509_FMT_PEM),
+					 { TRACE_DEBUG(INFO, "Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
+		free(dhparams.data);
+		
+	} else {
+		TRACE_DEBUG(INFO, "Generating fresh Diffie-Hellman parameters of size %d (this takes some time)... ", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS);
+		CHECK_GNUTLS_DO( gnutls_dh_params_generate2( 
+					fd_g_config->cnf_sec_data.dh_cache,
+					fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS),
+					 { TRACE_DEBUG(INFO, "Error in DH bits value : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
+	}			
+	
 	return 0;
 }
@@ -422,4 +467,5 @@
 	free(fd_g_config->cnf_sec_data.crl_file); fd_g_config->cnf_sec_data.crl_file = NULL;
 	free(fd_g_config->cnf_sec_data.prio_string); fd_g_config->cnf_sec_data.prio_string = NULL;
+	free(fd_g_config->cnf_sec_data.dh_file); fd_g_config->cnf_sec_data.dh_file = NULL;
 	
 	/* Destroy dictionary */
Index: freeDiameter/fdd.l
===================================================================
--- freeDiameter/fdd.l	(revision 258)
+++ freeDiameter/fdd.l	(revision 578)
@@ -137,4 +137,5 @@
 (?i:"TLS_Prio")		{ return TLS_PRIO;	}
 (?i:"TLS_DH_bits")	{ return TLS_DH_BITS;	}
+(?i:"TLS_DH_file")	{ return TLS_DH_FILE;	}
 
 
Index: freeDiameter/fdd.y
===================================================================
--- freeDiameter/fdd.y	(revision 308)
+++ freeDiameter/fdd.y	(revision 578)
@@ -118,4 +118,5 @@
 %token		TLS_PRIO
 %token		TLS_DH_BITS
+%token		TLS_DH_FILE
 
 
@@ -582,11 +583,18 @@
 			{
 				conf->cnf_sec_data.dh_bits = $3;
-				TRACE_DEBUG(FULL, "Generating DH parameters...");
-				CHECK_GNUTLS_DO( gnutls_dh_params_generate2( 
-							conf->cnf_sec_data.dh_cache,
-							conf->cnf_sec_data.dh_bits),
-						{ yyerror (&yylloc, conf, "Error setting DH Bits parameters."); 
-						 YYERROR; } );
-				TRACE_DEBUG(FULL, "DH parameters generated.");
-			}
-			;
+			}
+			| TLS_DH_FILE '=' QSTRING ';'
+			{
+				FILE * fd;
+				free(conf->cnf_sec_data.dh_file);
+				conf->cnf_sec_data.dh_file = $3;
+				fd = fopen($3, "r");
+				if (fd == NULL) {
+					int ret = errno;
+					TRACE_DEBUG(INFO, "Unable to open DH file %s for reading: %s\n", $3, strerror(ret));
+					yyerror (&yylloc, conf, "Error on file name"); 
+					YYERROR;
+				}
+				fclose(fd);
+			}
+			;
Index: include/freeDiameter/freeDiameter.h
===================================================================
--- include/freeDiameter/freeDiameter.h	(revision 542)
+++ include/freeDiameter/freeDiameter.h	(revision 578)
@@ -112,4 +112,5 @@
 		char *				 prio_string;
 		unsigned int 			 dh_bits;
+		char *				 dh_file;
 		
 		/* GNUTLS parameters */
