[exim-cvs] For DH, use standard primes from RFCs

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] For DH, use standard primes from RFCs
Gitweb: http://git.exim.org/exim.git/commitdiff/a799883d8ad340d935db4d729a31c02cb8a1d977
Commit:     a799883d8ad340d935db4d729a31c02cb8a1d977
Parent:     cae6e576b589efbe9e22cd65e5f890b21ce84f02
Author:     Phil Pennock <pdp@???>
AuthorDate: Sun May 27 09:14:39 2012 -0400
Committer:  Phil Pennock <pdp@???>
CommitDate: Sun May 27 09:14:39 2012 -0400


    For DH, use standard primes from RFCs
---
 doc/doc-docbook/spec.xfpt  |   68 +++++--
 doc/doc-txt/ChangeLog      |    5 +
 doc/doc-txt/GnuTLS-FAQ.txt |   16 +-
 doc/doc-txt/NewStuff       |    6 +
 src/OS/Makefile-Base       |    3 +-
 src/README.UPDATING        |   15 ++
 src/scripts/MakeLinks      |    1 +
 src/src/functions.h        |    4 +
 src/src/std-crypto.c       |  521 ++++++++++++++++++++++++++++++++++++++++++++
 src/src/tls-gnu.c          |   59 +++++-
 src/src/tls-openssl.c      |   88 +++++---
 src/util/gen_pkcs3.c       |  229 +++++++++++++++++++
 12 files changed, 958 insertions(+), 57 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 9c2bf19..beb0522 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -15706,14 +15706,43 @@ larger prime than requested.

.option tls_dhparam main string&!! unset
.cindex "TLS" "D-H parameters for server"
-The value of this option is expanded, and must then be the absolute path to
-a file which contains the server's DH parameter values.
-This is used only for OpenSSL. When Exim is linked with GnuTLS, this option is
-ignored. See section &<<SECTopenvsgnu>>& for further details.
-
.new
-If the DH bit-count from loading the file is greater than &%tls_dh_max_bits$&
-then it will be ignored.
+The value of this option is expanded and indicates the source of DH parameters
+to be used by Exim.
+
+If it is a filename starting with a &`/`&, then it names a file from which DH
+parameters should be loaded. If the file exists, it should hold a PEM-encoded
+PKCS#3 representation of the DH prime. If the file does not exist, for
+OpenSSL it is an error. For GnuTLS, Exim will attempt to create the file and
+fill it with a generated DH prime. For OpenSSL, if the DH bit-count from
+loading the file is greater than &%tls_dh_max_bits$& then it will be ignored,
+and treated as though the &%tls_dhparam%& were set to "none".
+
+If this option expands to the string "none", then no DH parameters will be
+loaded by Exim.
+
+If this option expands to the string "historic" and Exim is using GnuTLS, then
+Exim will attempt to load a file from inside the spool directory. If the file
+does not exist, Exim will attempt to create it.
+See section &<<SECTgnutlsparam>>& for further details.
+
+If Exim is using OpenSSL and this option is empty or unset, then Exim will load
+a default DH prime; the default is the 2048 bit prime described in section
+2.2 of RFC 5114, "2048-bit MODP Group with 224-bit Prime Order Subgroup", which
+in IKE is assigned number 23.
+
+Otherwise, the option must expand to the name used by Exim for any of a number
+of DH primes specified in RFC 2409, RFC 3526 and RFC 5114. As names, Exim uses
+"ike" followed by the number used by IKE, of "default" which corresponds to
+"ike23".
+
+The available primes are:
+&`ike1`&, &`ike2`&, &`ike5`&,
+&`ike14`&, &`ike15`&, &`ike16`&, &`ike17`&, &`ike18`&,
+&`ike22`&, &`ike23`& (aka &`default`&) and &`ike24`&.
+
+Some of these will be too small to be accepted by clients.
+Some may be too large to be accepted by clients.
.wen


@@ -25000,12 +25029,8 @@ There are some differences in usage when using GnuTLS instead of OpenSSL:
The &%tls_verify_certificates%& option must contain the name of a file, not the
name of a directory (for OpenSSL it can be either).
.next
-The &%tls_dhparam%& option is ignored, because early versions of GnuTLS had no
-facility for varying its Diffie-Hellman parameters.
.new
-Since then, the GnuTLS support has been updated to generate parameters upon
-demand, keeping them in the spool directory. See &<<SECTgnutlsparam>>& for
-details.
+The default value for &%tls_dhparam%& differs for historical reasons.
.wen
.next
.vindex "&$tls_peerdn$&"
@@ -25284,13 +25309,24 @@ this). There is one other option that may be needed in other situations. If
tls_dhparam = /some/file/name
.endd
is set, the SSL library is initialized for the use of Diffie-Hellman ciphers
-with the parameters contained in the file. This increases the set of cipher
-suites that the server supports. See the command
+with the parameters contained in the file.
+.new
+Set this to &`none`& to disable use of DH entirely, by making no prime
+available:
+.code
+tls_dhparam = none
+.endd
+This may also be set to a string identifying a standard prime to be used for
+DH; if it is set to &`default`& or, for OpenSSL, is unset, then the prime
+used is &`ike23`&. There are a few standard primes available, see the
+documetnation for &%tls_dhparam%& for the complete list.
+
+See the command
.code
openssl dhparam
.endd
-for a way of generating this data. At present, &%tls_dhparam%& is used only
-when Exim is linked with OpenSSL. It is ignored if GnuTLS is being used.
+for a way of generating file data.
+.wen

 The strings supplied for these three options are expanded every time a client
 host connects. It is therefore possible to use different certificates and keys
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index e7b807e..4f8154c 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -158,6 +158,11 @@ PP/37 Unbreak Cyrus SASL auth: SSF retrieval was incorrect, Exim thought
       protection layer was required, which is not implemented.
       Bugzilla 1254, patch from Wolfgang Breyha.


+PP/38 Overhaul DH prime handling, supply RFC-specified DH primes as built
+      into Exim, default to IKE id 23 from RFC 5114 (2048 bit).  Make
+      tls_dhparam take prime identifiers.  Also unbreak combination of
+      OpenSSL+DH_params+TLSSNI.
+


Exim version 4.77
-----------------
diff --git a/doc/doc-txt/GnuTLS-FAQ.txt b/doc/doc-txt/GnuTLS-FAQ.txt
index 4339bec..8d5887b 100644
--- a/doc/doc-txt/GnuTLS-FAQ.txt
+++ b/doc/doc-txt/GnuTLS-FAQ.txt
@@ -143,6 +143,10 @@ connections.
(6): What's the deal with tls_dh_max_bits? What's DH?
------------------------------------------------------

+You can avoid all of the tls_dh_max_bits issues if you leave "tls_dhparam"
+unset, so that you get one of the standard built-in primes used for DH.
+
+
DH, Diffie-Hellman (or Diffie-Hellman-Merkle, or something naming Williamson)
is the common name for a way for two parties to a communication stream to
exchange some private random data so that both end up with a shared secret
@@ -258,9 +262,15 @@ Ideally, the first line will read "PKCS#3 DH Parameters: (2236 bit)". If the
count is more than 2236, then remove the file and let Exim regenerate it, or
generate one yourself and move it into place. Ideally use "openssl dhparam"
to generate it, and then wait a very long time; at least this way, the size
-will be correct. (This developer is now convinced that Exim 4.81 should
-bundle the suggested primes from a few RFCs and let the administrator choose
-those.)
+will be correct.
+
+The use of "hope" as a strategy was felt to be unacceptable as a default, so
+late in the RC series for 4.80, the whole issue was side-stepped. The primes
+used for DH are publicly revealed; moreover, there are selection criteria for
+what makes a "good" DH prime. As it happens, there are *standard* primes
+which can be used, and are specified to be used for certain protocols. So
+these primes were built into Exim, and by default exim now uses a 2048 bit
+prime from section 2.2 of RFC 5114.


 A TLS client does not get to choose the DH prime used, but can choose a
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 5999444..0c3fccb 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -100,6 +100,12 @@ Version 4.80
     hard-coded limit of DH ephemeral bits, to fix interop problems caused by
     GnuTLS 2.12 library recommending a bit count higher than NSS supports.


+16. tls_dhparam now used by both OpenSSL and GnuTLS, can be path or identifier.
+    Option can now be a path or an identifier for a standard prime.
+    If unset, we use the DH prime from section 2.2 of RFC 5114, "ike23".
+    Set to "historic" to get the old GnuTLS behaviour of auto-generated DH
+    primes.
+


 Version 4.77
 ------------
diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base
index de387e0..2812945 100644
--- a/src/OS/Makefile-Base
+++ b/src/OS/Makefile-Base
@@ -312,7 +312,7 @@ OBJ_EXIM = acl.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
         os.o parse.o queue.o \
         rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \
         route.o search.o sieve.o smtp_in.o smtp_out.o spool_in.o spool_out.o \
-        store.o string.o tls.o tod.o transport.o tree.o verify.o \
+        std-crypto.o store.o string.o tls.o tod.o transport.o tree.o verify.o \
         $(OBJ_LOOKUPS) \
         local_scan.o $(EXIM_PERL) $(OBJ_WITH_CONTENT_SCAN) \
         $(OBJ_WITH_OLD_DEMIME) $(OBJ_EXPERIMENTAL)
@@ -575,6 +575,7 @@ smtp_in.o:       $(HDRS) smtp_in.c
 smtp_out.o:      $(HDRS) smtp_out.c
 spool_in.o:      $(HDRS) spool_in.c
 spool_out.o:     $(HDRS) spool_out.c
+std-crypto.o:    $(HDRS) std-crypto.c
 store.o:         $(HDRS) store.c
 string.o:        $(HDRS) string.c
 tls.o:           $(HDRS) tls.c tls-gnu.c tls-openssl.c
diff --git a/src/README.UPDATING b/src/README.UPDATING
index a15bd41..6a820bc 100644
--- a/src/README.UPDATING
+++ b/src/README.UPDATING
@@ -142,6 +142,21 @@ Exim version 4.80
    fail completely.  (The check is not done as root, to ensure that problems
    here are not made worse by the check).


+ * The "tls_dhparam" option has been updated, so that it can now specify a
+ path or an identifier for a standard DH prime from one of a few RFCs.
+ The default for OpenSSL is no longer to not use DH but instead to use
+ one of these standard primes. The default for GnuTLS is no longer to use
+ a file in the spool directory, but to use that same standard prime.
+ The option is now used by GnuTLS too. If it points to a path, then
+ GnuTLS will use that path, instead of a file in the spool directory;
+ GnuTLS will attempt to create it if it does not exist.
+
+ To preserve the previous behaviour of generating files in the spool
+ directory, set "tls_dhparam = historic". Since prior releases of Exim
+ ignored tls_dhparam when using GnuTLS, this can safely be done before
+ the upgrade.
+
+

 Exim version 4.77
 -----------------
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index 166a25f..62d248a 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -228,6 +228,7 @@ ln -s ../src/smtp_in.c         smtp_in.c
 ln -s ../src/smtp_out.c        smtp_out.c
 ln -s ../src/spool_in.c        spool_in.c
 ln -s ../src/spool_out.c       spool_out.c
+ln -s ../src/std-crypto.c      std-crypto.c
 ln -s ../src/store.c           store.c
 ln -s ../src/string.c          string.c
 ln -s ../src/tls.c             tls.c
diff --git a/src/src/functions.h b/src/src/functions.h
index 160f513..29e7db2 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -21,6 +21,10 @@ extern uschar *init_perl(uschar *);



 #ifdef SUPPORT_TLS
+extern const char *
+               std_dh_prime_default(void);
+extern const char *
+               std_dh_prime_named(const uschar *);
 extern int     tls_client_start(int, host_item *, address_item *, uschar *,
                  uschar *, uschar *, uschar *, uschar *, uschar *, uschar *,
                  int);
diff --git a/src/src/std-crypto.c b/src/src/std-crypto.c
new file mode 100644
index 0000000..3f0fec8
--- /dev/null
+++ b/src/src/std-crypto.c
@@ -0,0 +1,521 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) Phil Pennock 2012
+ * But almost everything here is fixed published constants from RFCs, so also:
+ * Copyright (C) The Internet Society (2003)
+ * Copyright (C) The IETF Trust (2008)
+ * Most of the text in RFC referencing comments is copy/paste from RFC,
+ * as is undoubtedly the intention.
+ * The constants are generated from that text using util/gen_pkcs3.c invoked
+ * with the -C option.
+ */
+
+/* See the file NOTICE for conditions of use and distribution. */
+
+#include "exim.h"
+
+#ifndef SUPPORT_TLS
+static void dummy(int x) { dummy(x-1); }
+#else
+
+/* The IETF defines standard primes as "Modular Exponential (MODP) Groups" for
+use in IKE in RFC 2409 and 3526, and then some more, "for Use with IETF
+Standards" in RFC 5114.  These have been thoroughly reviewed as meeting
+certain eligibility criteria, which is more than can be said for primes
+generated quickly on no particular criteria.
+
+Any prime used in TLS is disclosed publicly, and if the security of your
+session depends upon the prime being secret, then one of three situations
+holds:
+ (1) the prime is too small
+ (2) the prime is flawed, use one of these instead
+ (3) you know of fundamental cryptanalytic breaks not currently publicly known
+     to the cryptographic community.
+*/
+
+/* RFC 2409 MODP IKE_id=1 generator=2 bits=768
+   The prime is: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
+   Its hexadecimal value is
+         FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+         29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+         EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+         E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF
+*/
+static const char dh_ike_1_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MGYCYQD//////////8kP2qIhaMI0xMZii4DcHNEpAk4IimfMdAILvqY7E5siUUoI\n"
+"eY40BN3vlRmzzTpDGzArCm3yXxQ3T+E1bW1RwkXkhbV2Yl5+xvRMQummOjYg////\n"
+"//////8CAQI=\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 2409 MODP IKE_id=2 generator=2 bits=1024
+   The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
+   Its hexadecimal value is
+
+         FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+         29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+         EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+         E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+         EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381
+         FFFFFFFF FFFFFFFF
+*/
+static const char dh_ike_2_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR\n"
+"Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL\n"
+"/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 2409; id=3 and id=4 are EC2N, not yet supported here */
+
+/* RFC 3526 MODP IKE_id=5 generator=2 bits=1536
+   The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
+   Its hexadecimal value is:
+
+      FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+      29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+      EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+      E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+      EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+      C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+      83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+      670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF
+*/
+static const char dh_ike_5_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIHHAoHBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR\n"
+"Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL\n"
+"/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7ORbPcIAfLihY78FmNpINhxV05pp\n"
+"Fj+o/STPX4NlXSPco62WHGLzViCFUrue1SkHcJaWbWcMNU5KvJgE8XRsCMojcyf/\n"
+"/////////wIBAg==\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 3526 MODP IKE_id=14 generator=2 bits=2048
+   This prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
+   Its hexadecimal value is:
+
+      FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+      29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+      EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+      E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+      EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+      C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+      83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+      670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+      E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+      DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+      15728E5A 8AACAA68 FFFFFFFF FFFFFFFF
+*/
+static const char dh_ike_14_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n"
+"IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n"
+"awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n"
+"mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n"
+"fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n"
+"5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 3526 MODP IKE_id=15 generator=2 bits=3072
+   This prime is: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }
+   Its hexadecimal value is:
+
+      FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+      29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+      EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+      E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+      EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+      C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+      83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+      670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+      E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+      DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+      15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64
+      ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7
+      ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B
+      F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
+      BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31
+      43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF
+*/
+static const char dh_ike_15_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIIBiAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n"
+"IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n"
+"awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n"
+"mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n"
+"fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n"
+"5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM\n"
+"fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq\n"
+"ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS\n"
+"yv//////////AgEC\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 3526 MODP IKE_id=16 generator=2 bits=4096
+   This prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
+   Its hexadecimal value is:
+
+      FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+      29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+      EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+      E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+      EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+      C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+      83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+      670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+      E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+      DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+      15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64
+      ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7
+      ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B
+      F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
+      BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31
+      43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7
+      88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA
+      2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6
+      287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED
+      1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9
+      93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199
+      FFFFFFFF FFFFFFFF
+*/
+static const char dh_ike_16_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n"
+"IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n"
+"awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n"
+"mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n"
+"fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n"
+"5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM\n"
+"fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq\n"
+"ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI\n"
+"ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O\n"
+"+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI\n"
+"HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQI=\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 3526 MODP IKE_id=17 generator=2 bits=6144
+   This prime is: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }
+   Its hexadecimal value is:
+
+   FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08
+   8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B
+   302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9
+   A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6
+   49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8
+   FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+   670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C
+   180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718
+   3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D
+   04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D
+   B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226
+   1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
+   BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC
+   E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7 88719A10 BDBA5B26
+   99C32718 6AF4E23C 1A946834 B6150BDA 2583E9CA 2AD44CE8 DBBBC2DB
+   04DE8EF9 2E8EFC14 1FBECAA6 287C5947 4E6BC05D 99B2964F A090C3A2
+   233BA186 515BE7ED 1F612970 CEE2D7AF B81BDD76 2170481C D0069127
+   D5B05AA9 93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492
+   36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD F8FF9406
+   AD9E530E E5DB382F 413001AE B06A53ED 9027D831 179727B0 865A8918
+   DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B DB7F1447 E6CC254B 33205151
+   2BD7AF42 6FB8F401 378CD2BF 5983CA01 C64B92EC F032EA15 D1721D03
+   F482D7CE 6E74FEF6 D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F
+   BEC7E8F3 23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA
+   CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328 06A1D58B
+   B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C DA56C9EC 2EF29632
+   387FE8D7 6E3C0468 043E8F66 3F4860EE 12BF2D5B 0B7474D6 E694F91E
+   6DCC4024 FFFFFFFF FFFFFFFF
+*/
+static const char dh_ike_17_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIIDCAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n"
+"IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n"
+"awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n"
+"mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n"
+"fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n"
+"5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM\n"
+"fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq\n"
+"ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI\n"
+"ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O\n"
+"+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI\n"
+"HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG\n"
+"3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU\n"
+"7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId\n"
+"A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha\n"
+"xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/\n"
+"8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA\n"
+"JP//////////AgEC\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 3526 MODP IKE_id=18 generator=2 bits=8192
+   This prime is: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }
+   Its hexadecimal value is:
+
+      FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+      29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+      EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+      E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+      EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+      C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+      83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+      670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+      E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+      DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+      15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64
+      ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7
+      ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B
+      F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C
+      BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31
+      43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7
+      88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA
+      2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6
+      287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED
+      1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9
+      93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34028492
+      36C3FAB4 D27C7026 C1D4DCB2 602646DE C9751E76 3DBA37BD
+      F8FF9406 AD9E530E E5DB382F 413001AE B06A53ED 9027D831
+      179727B0 865A8918 DA3EDBEB CF9B14ED 44CE6CBA CED4BB1B
+      DB7F1447 E6CC254B 33205151 2BD7AF42 6FB8F401 378CD2BF
+      5983CA01 C64B92EC F032EA15 D1721D03 F482D7CE 6E74FEF6
+      D55E702F 46980C82 B5A84031 900B1C9E 59E7C97F BEC7E8F3
+      23A97A7E 36CC88BE 0F1D45B7 FF585AC5 4BD407B2 2B4154AA
+      CC8F6D7E BF48E1D8 14CC5ED2 0F8037E0 A79715EE F29BE328
+      06A1D58B B7C5DA76 F550AA3D 8A1FBFF0 EB19CCB1 A313D55C
+      DA56C9EC 2EF29632 387FE8D7 6E3C0468 043E8F66 3F4860EE
+      12BF2D5B 0B7474D6 E694F91E 6DBE1159 74A3926F 12FEE5E4
+      38777CB6 A932DF8C D8BEC4D0 73B931BA 3BC832B6 8D9DD300
+      741FA7BF 8AFC47ED 2576F693 6BA42466 3AAB639C 5AE4F568
+      3423B474 2BF1C978 238F16CB E39D652D E3FDB8BE FC848AD9
+      22222E04 A4037C07 13EB57A8 1A23F0C7 3473FC64 6CEA306B
+      4BCBC886 2F8385DD FA9D4B7F A2C087E8 79683303 ED5BDD3A
+      062B3CF5 B3A278A6 6D2A13F8 3F44F82D DF310EE0 74AB6A36
+      4597E899 A0255DC1 64F31CC5 0846851D F9AB4819 5DED7EA1
+      B1D510BD 7EE74D73 FAF36BC3 1ECFA268 359046F4 EB879F92
+      4009438B 481C6CD7 889A002E D5EE382B C9190DA6 FC026E47
+      9558E447 5677E9AA 9E3050E2 765694DF C81F56E8 80B96E71
+      60C980DD 98EDD3DF FFFFFFFF FFFFFFFF
+*/
+static const char dh_ike_18_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIIECAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n"
+"IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n"
+"awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n"
+"mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n"
+"fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n"
+"5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM\n"
+"fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq\n"
+"ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI\n"
+"ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O\n"
+"+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI\n"
+"HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG\n"
+"3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU\n"
+"7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId\n"
+"A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha\n"
+"xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/\n"
+"8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R\n"
+"WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk\n"
+"ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw\n"
+"xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4\n"
+"Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i\n"
+"aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU\n"
+"38gfVuiAuW5xYMmA3Zjt09///////////wIBAg==\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 5114 IKE_id=22
+2.1.  1024-bit MODP Group with 160-bit Prime Order Subgroup
+
+   The hexadecimal value of the prime is:
+
+   p = B10B8F96 A080E01D DE92DE5E AE5D54EC 52C99FBC FB06A3C6
+       9A6A9DCA 52D23B61 6073E286 75A23D18 9838EF1E 2EE652C0
+       13ECB4AE A9061123 24975C3C D49B83BF ACCBDD7D 90C4BD70
+       98488E9C 219A7372 4EFFD6FA E5644738 FAA31A4F F55BCCC0
+       A151AF5F 0DC8B4BD 45BF37DF 365C1A65 E68CFDA7 6D4DA708
+       DF1FB2BC 2E4A4371
+
+   The hexadecimal value of the generator is:
+
+   g = A4D1CBD5 C3FD3412 6765A442 EFB99905 F8104DD2 58AC507F
+       D6406CFF 14266D31 266FEA1E 5C41564B 777E690F 5504F213
+       160217B4 B01B886A 5E91547F 9E2749F4 D7FBD7D3 B9A92EE1
+       909D0D22 63F80A76 A6A24C08 7A091F53 1DBF0A01 69B6A28A
+       D662A4D1 8E73AFA3 2D779D59 18D08BC8 858F4DCE F97C2A24
+       855E6EEB 22B3B2E5
+
+   The generator generates a prime-order subgroup of size:
+
+   q = F518AA87 81A8DF27 8ABA4E7D 64B7CB9D 49462353
+*/
+static const char dh_ike_22_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIIBCAKBgQCxC4+WoIDgHd6S3l6uXVTsUsmfvPsGo8aaap3KUtI7YWBz4oZ1oj0Y\n"
+"mDjvHi7mUsAT7LSuqQYRIySXXDzUm4O/rMvdfZDEvXCYSI6cIZpzck7/1vrlZEc4\n"
+"+qMaT/VbzMChUa9fDci0vUW/N982XBpl5oz9p21NpwjfH7K8LkpDcQKBgQCk0cvV\n"
+"w/00EmdlpELvuZkF+BBN0lisUH/WQGz/FCZtMSZv6h5cQVZLd35pD1UE8hMWAhe0\n"
+"sBuIal6RVH+eJ0n01/vX07mpLuGQnQ0iY/gKdqaiTAh6CR9THb8KAWm2oorWYqTR\n"
+"jnOvoy13nVkY0IvIhY9Nzvl8KiSFXm7rIrOy5Q==\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 5114 IKE_id=23
+2.2.  2048-bit MODP Group with 224-bit Prime Order Subgroup
+
+   The hexadecimal value of the prime is:
+
+   p =  AD107E1E 9123A9D0 D660FAA7 9559C51F A20D64E5 683B9FD1
+        B54B1597 B61D0A75 E6FA141D F95A56DB AF9A3C40 7BA1DF15
+        EB3D688A 309C180E 1DE6B85A 1274A0A6 6D3F8152 AD6AC212
+        9037C9ED EFDA4DF8 D91E8FEF 55B7394B 7AD5B7D0 B6C12207
+        C9F98D11 ED34DBF6 C6BA0B2C 8BBC27BE 6A00E0A0 B9C49708
+        B3BF8A31 70918836 81286130 BC8985DB 1602E714 415D9330
+        278273C7 DE31EFDC 7310F712 1FD5A074 15987D9A DC0A486D
+        CDF93ACC 44328387 315D75E1 98C641A4 80CD86A1 B9E587E8
+        BE60E69C C928B2B9 C52172E4 13042E9B 23F10B0E 16E79763
+        C9B53DCF 4BA80A29 E3FB73C1 6B8E75B9 7EF363E2 FFA31F71
+        CF9DE538 4E71B81C 0AC4DFFE 0C10E64F
+
+   The hexadecimal value of the generator is:
+
+   g =  AC4032EF 4F2D9AE3 9DF30B5C 8FFDAC50 6CDEBE7B 89998CAF
+        74866A08 CFE4FFE3 A6824A4E 10B9A6F0 DD921F01 A70C4AFA
+        AB739D77 00C29F52 C57DB17C 620A8652 BE5E9001 A8D66AD7
+        C1766910 1999024A F4D02727 5AC1348B B8A762D0 521BC98A
+        E2471504 22EA1ED4 09939D54 DA7460CD B5F6C6B2 50717CBE
+        F180EB34 118E98D1 19529A45 D6F83456 6E3025E3 16A330EF
+        BB77A86F 0C1AB15B 051AE3D4 28C8F8AC B70A8137 150B8EEB
+        10E183ED D19963DD D9E263E4 770589EF 6AA21E7F 5F2FF381
+        B539CCE3 409D13CD 566AFBB4 8D6C0191 81E1BCFE 94B30269
+        EDFE72FE 9B6AA4BD 7B5A0F1C 71CFFF4C 19C418E1 F6EC0179
+        81BC087F 2A7065B3 84B890D3 191F2BFA
+
+   The generator generates a prime-order subgroup of size:
+
+   q =  801C0D34 C58D93FE 99717710 1F80535A 4738CEBC BF389A99
+        B36371EB
+*/
+static const char dh_ike_23_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIICCgKCAQEArRB+HpEjqdDWYPqnlVnFH6INZOVoO5/RtUsVl7YdCnXm+hQd+VpW\n"
+"26+aPEB7od8V6z1oijCcGA4d5rhaEnSgpm0/gVKtasISkDfJ7e/aTfjZHo/vVbc5\n"
+"S3rVt9C2wSIHyfmNEe002/bGugssi7wnvmoA4KC5xJcIs7+KMXCRiDaBKGEwvImF\n"
+"2xYC5xRBXZMwJ4Jzx94x79xzEPcSH9WgdBWYfZrcCkhtzfk6zEQyg4cxXXXhmMZB\n"
+"pIDNhqG55YfovmDmnMkosrnFIXLkEwQumyPxCw4W55djybU9z0uoCinj+3PBa451\n"
+"uX7zY+L/ox9xz53lOE5xuBwKxN/+DBDmTwKCAQEArEAy708tmuOd8wtcj/2sUGze\n"
+"vnuJmYyvdIZqCM/k/+OmgkpOELmm8N2SHwGnDEr6q3OddwDCn1LFfbF8YgqGUr5e\n"
+"kAGo1mrXwXZpEBmZAkr00CcnWsE0i7inYtBSG8mK4kcVBCLqHtQJk51U2nRgzbX2\n"
+"xrJQcXy+8YDrNBGOmNEZUppF1vg0Vm4wJeMWozDvu3eobwwasVsFGuPUKMj4rLcK\n"
+"gTcVC47rEOGD7dGZY93Z4mPkdwWJ72qiHn9fL/OBtTnM40CdE81Wavu0jWwBkYHh\n"
+"vP6UswJp7f5y/ptqpL17Wg8ccc//TBnEGOH27AF5gbwIfypwZbOEuJDTGR8r+g==\n"
+"-----END DH PARAMETERS-----\n";
+
+/* RFC 5114 IKE_id=24
+2.3.  2048-bit MODP Group with 256-bit Prime Order Subgroup
+
+   The hexadecimal value of the prime is:
+
+   p = 87A8E61D B4B6663C FFBBD19C 65195999 8CEEF608 660DD0F2
+       5D2CEED4 435E3B00 E00DF8F1 D61957D4 FAF7DF45 61B2AA30
+       16C3D911 34096FAA 3BF4296D 830E9A7C 209E0C64 97517ABD
+       5A8A9D30 6BCF67ED 91F9E672 5B4758C0 22E0B1EF 4275BF7B
+       6C5BFC11 D45F9088 B941F54E B1E59BB8 BC39A0BF 12307F5C
+       4FDB70C5 81B23F76 B63ACAE1 CAA6B790 2D525267 35488A0E
+       F13C6D9A 51BFA4AB 3AD83477 96524D8E F6A167B5 A41825D9
+       67E144E5 14056425 1CCACB83 E6B486F6 B3CA3F79 71506026
+       C0B857F6 89962856 DED4010A BD0BE621 C3A3960A 54E710C3
+       75F26375 D7014103 A4B54330 C198AF12 6116D227 6E11715F
+       693877FA D7EF09CA DB094AE9 1E1A1597
+
+   The hexadecimal value of the generator is:
+
+   g = 3FB32C9B 73134D0B 2E775066 60EDBD48 4CA7B18F 21EF2054
+       07F4793A 1A0BA125 10DBC150 77BE463F FF4FED4A AC0BB555
+       BE3A6C1B 0C6B47B1 BC3773BF 7E8C6F62 901228F8 C28CBB18
+       A55AE313 41000A65 0196F931 C77A57F2 DDF463E5 E9EC144B
+       777DE62A AAB8A862 8AC376D2 82D6ED38 64E67982 428EBC83
+       1D14348F 6F2F9193 B5045AF2 767164E1 DFC967C1 FB3F2E55
+       A4BD1BFF E83B9C80 D052B985 D182EA0A DB2A3B73 13D3FE14
+       C8484B1E 052588B9 B7D2BBD2 DF016199 ECD06E15 57CD0915
+       B3353BBB 64E0EC37 7FD02837 0DF92B52 C7891428 CDC67EB6
+       184B523D 1DB246C3 2F630784 90F00EF8 D647D148 D4795451
+       5E2327CF EF98C582 664B4C0F 6CC41659
+
+   The generator generates a prime-order subgroup of size:
+
+   q = 8CF83642 A709A097 B4479976 40129DA2 99B1A47D 1EB3750B
+       A308B0FE 64F5FBD3
+*/
+static const char dh_ike_24_pem[] =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIICCQKCAQEAh6jmHbS2Zjz/u9GcZRlZmYzu9ghmDdDyXSzu1ENeOwDgDfjx1hlX\n"
+"1Pr330VhsqowFsPZETQJb6o79Cltgw6afCCeDGSXUXq9WoqdMGvPZ+2R+eZyW0dY\n"
+"wCLgse9Cdb97bFv8EdRfkIi5QfVOseWbuLw5oL8SMH9cT9twxYGyP3a2Osrhyqa3\n"
+"kC1SUmc1SIoO8TxtmlG/pKs62DR3llJNjvahZ7WkGCXZZ+FE5RQFZCUcysuD5rSG\n"
+"9rPKP3lxUGAmwLhX9omWKFbe1AEKvQvmIcOjlgpU5xDDdfJjddcBQQOktUMwwZiv\n"
+"EmEW0iduEXFfaTh3+tfvCcrbCUrpHhoVlwKCAQA/syybcxNNCy53UGZg7b1ITKex\n"
+"jyHvIFQH9Hk6GguhJRDbwVB3vkY//0/tSqwLtVW+OmwbDGtHsbw3c79+jG9ikBIo\n"
+"+MKMuxilWuMTQQAKZQGW+THHelfy3fRj5ensFEt3feYqqrioYorDdtKC1u04ZOZ5\n"
+"gkKOvIMdFDSPby+Rk7UEWvJ2cWTh38lnwfs/LlWkvRv/6DucgNBSuYXRguoK2yo7\n"
+"cxPT/hTISEseBSWIubfSu9LfAWGZ7NBuFVfNCRWzNTu7ZODsN3/QKDcN+StSx4kU\n"
+"KM3GfrYYS1I9HbJGwy9jB4SQ8A741kfRSNR5VFFeIyfP75jFgmZLTA9sxBZZ\n"
+"-----END DH PARAMETERS-----\n";
+
+
+/* ========================================================================= */
+
+struct dh_constant {
+  const char *label;
+  const char *pem;
+};
+
+/* KEEP SORTED ALPHABETICALLY;
+ * duplicate PEM are okay, if we want aliases, but names must be alphabetical */
+static struct dh_constant dh_constants[] = {
+    { "default", dh_ike_23_pem },
+    { "ike1", dh_ike_1_pem },
+    { "ike14", dh_ike_14_pem },
+    { "ike15", dh_ike_15_pem },
+    { "ike16", dh_ike_16_pem },
+    { "ike17", dh_ike_17_pem },
+    { "ike18", dh_ike_18_pem },
+    { "ike2", dh_ike_2_pem },
+    { "ike22", dh_ike_22_pem },
+    { "ike23", dh_ike_23_pem },
+    { "ike24", dh_ike_24_pem },
+    { "ike5", dh_ike_5_pem },
+};
+static const int dh_constants_count =
+  sizeof(dh_constants) / sizeof(struct dh_constant);
+
+
+/* A policy decision; in absence of any other data, use a 2048 bit prime,
+ * pick the first one from the latest RFC providing such. */
+const char *
+std_dh_prime_default(void)
+{
+  return dh_ike_23_pem;
+}
+
+
+const char *
+std_dh_prime_named(const uschar *name)
+{
+  int first, last;
+  char *search_name = CS string_copylc(US name);
+
+  first = 0;
+  last = dh_constants_count;
+  while (last > first) {
+    int middle = (first + last)/2;
+    int c = strcmp(search_name, dh_constants[middle].label);
+    if (c == 0)
+      return dh_constants[middle].pem;
+    else if (c > 0)
+      first = middle + 1;
+    else
+      last = middle;
+  }
+  return NULL;
+}
+
+#endif /* SUPPORT_TLS */
+/* EOF */
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
index e2fcb33..7aab309 100644
--- a/src/src/tls-gnu.c
+++ b/src/src/tls-gnu.c
@@ -358,9 +358,6 @@ file is never present. If two processes both compute some new parameters, you
 waste a bit of effort, but it doesn't seem worth messing around with locking to
 prevent this.


-Argument:
-  host       NULL for server, server for client (for error handling)
-
 Returns:     OK/DEFER/FAIL
 */


@@ -370,8 +367,12 @@ init_server_dh(void)
int fd, rc;
unsigned int dh_bits;
gnutls_datum m;
-uschar filename[PATH_MAX];
+uschar filename_buf[PATH_MAX];
+uschar *filename = NULL;
size_t sz;
+uschar *exp_tls_dhparam;
+BOOL use_file_in_spool = FALSE;
+BOOL use_fixed_file = FALSE;
host_item *host = NULL; /* dummy for macros */

DEBUG(D_tls) debug_printf("Initialising GnuTLS server params.\n");
@@ -379,6 +380,46 @@ DEBUG(D_tls) debug_printf("Initialising GnuTLS server params.\n");
rc = gnutls_dh_params_init(&dh_server_params);
exim_gnutls_err_check(US"gnutls_dh_params_init");

+m.data = NULL;
+m.size = 0;
+
+if (!expand_check(tls_dhparam, US"tls_dhparam", &exp_tls_dhparam))
+  return DEFER;
+
+if (!exp_tls_dhparam)
+  {
+  DEBUG(D_tls) debug_printf("Loading default hard-coded DH params\n");
+  m.data = US std_dh_prime_default();
+  m.size = Ustrlen(m.data);
+  }
+else if (Ustrcmp(exp_tls_dhparam, "historic") == 0)
+  use_file_in_spool = TRUE;
+else if (Ustrcmp(exp_tls_dhparam, "none") == 0)
+  {
+  DEBUG(D_tls) debug_printf("Requested no DH parameters.\n");
+  return OK;
+  }
+else if (exp_tls_dhparam[0] != '/')
+  {
+  m.data = US std_dh_prime_named(exp_tls_dhparam);
+  if (m.data == NULL)
+    return tls_error(US"No standard prime named", CS exp_tls_dhparam, NULL);
+  m.size = Ustrlen(m.data);
+  }
+else
+  {
+  use_fixed_file = TRUE;
+  filename = exp_tls_dhparam;
+  }
+
+if (m.data)
+  {
+  rc = gnutls_dh_params_import_pkcs3(dh_server_params, &m, GNUTLS_X509_FMT_PEM);
+  exim_gnutls_err_check(US"gnutls_dh_params_import_pkcs3");
+  DEBUG(D_tls) debug_printf("Loaded fixed standard D-H parameters\n");
+  return OK;
+  }
+
 #ifdef HAVE_GNUTLS_SEC_PARAM_CONSTANTS
 /* If you change this constant, also change dh_param_fn_ext so that we can use a
 different filename and ensure we have sufficient bits. */
@@ -404,9 +445,13 @@ if (dh_bits > tls_dh_max_bits)
   dh_bits = tls_dh_max_bits;
   }


-if (!string_format(filename, sizeof(filename),
-      "%s/gnutls-params-%d", spool_directory, dh_bits))
-  return tls_error(US"overlong filename", NULL, NULL);
+if (use_file_in_spool)
+  {
+  if (!string_format(filename_buf, sizeof(filename_buf),
+        "%s/gnutls-params-%d", spool_directory, dh_bits))
+    return tls_error(US"overlong filename", NULL, NULL);
+  filename = filename_buf;
+  }


/* Open the cache file for reading and if successful, read it and set up the
parameters. */
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index ebc5a62..43b7963 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -275,60 +275,85 @@ DEBUG(D_tls) debug_printf("SSL info: %s\n", SSL_state_string_long(s));
/* If dhparam is set, expand it, and load up the parameters for DH encryption.

 Arguments:
-  dhparam   DH parameter file
+  dhparam   DH parameter file or fixed parameter identity string
   host      connected host, if client; NULL if server


 Returns:    TRUE if OK (nothing to set up, or setup worked)
 */


static BOOL
-init_dh(uschar *dhparam, host_item *host)
+init_dh(SSL_CTX *sctx, uschar *dhparam, host_item *host)
{
-BOOL yield = TRUE;
BIO *bio;
DH *dh;
uschar *dhexpanded;
+const char *pem;

if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded))
return FALSE;

-if (dhexpanded == NULL) return TRUE;
-
-if ((bio = BIO_new_file(CS dhexpanded, "r")) == NULL)
+if (dhexpanded == NULL || *dhexpanded == '\0')
   {
-  tls_error(string_sprintf("could not read dhparams file %s", dhexpanded),
-    host, (uschar *)strerror(errno));
-  yield = FALSE;
+  bio = BIO_new_mem_buf(CS std_dh_prime_default(), -1);
   }
-else
+else if (dhexpanded[0] == '/')
   {
-  if ((dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)) == NULL)
+  bio = BIO_new_file(CS dhexpanded, "r");
+  if (bio == NULL)
     {
     tls_error(string_sprintf("could not read dhparams file %s", dhexpanded),
-      host, NULL);
-    yield = FALSE;
+          host, US strerror(errno));
+    return FALSE;
     }
-  else
+  }
+else
+  {
+  if (Ustrcmp(dhexpanded, "none") == 0)
     {
-    if ((8*DH_size(dh)) > tls_dh_max_bits)
-      {
-      DEBUG(D_tls)
-        debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d",
-            8*DH_size(dh), tls_dh_max_bits);
-      }
-    else
-      {
-      SSL_CTX_set_tmp_dh(ctx, dh);
-      DEBUG(D_tls)
-        debug_printf("Diffie-Hellman initialized from %s with %d-bit key\n",
-          dhexpanded, 8*DH_size(dh));
-      }
-    DH_free(dh);
+    DEBUG(D_tls) debug_printf("Requested no DH parameters.\n");
+    return TRUE;
+    }
+
+  pem = std_dh_prime_named(dhexpanded);
+  if (!pem)
+    {
+    tls_error(string_sprintf("Unknown standard DH prime \"%s\"", dhexpanded),
+        host, US strerror(errno));
+    return FALSE;
     }
+  bio = BIO_new_mem_buf(CS pem, -1);
+  }
+
+dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+if (dh == NULL)
+  {
   BIO_free(bio);
+  tls_error(string_sprintf("Could not read tls_dhparams \"%s\"", dhexpanded),
+      host, NULL);
+  return FALSE;
   }


-return yield;
+/* Even if it is larger, we silently return success rather than cause things
+ * to fail out, so that a too-large DH will not knock out all TLS; it's a
+ * debatable choice. */
+if ((8*DH_size(dh)) > tls_dh_max_bits)
+  {
+  DEBUG(D_tls)
+    debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d",
+        8*DH_size(dh), tls_dh_max_bits);
+  }
+else
+  {
+  SSL_CTX_set_tmp_dh(sctx, dh);
+  DEBUG(D_tls)
+    debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n",
+      dhexpanded ? dhexpanded : US"default", 8*DH_size(dh));
+  }
+
+DH_free(dh);
+BIO_free(bio);
+
+return TRUE;
 }



@@ -619,6 +644,9 @@ OCSP information. */
rc = tls_expand_session_files(ctx_sni, cbinfo);
if (rc != OK) return SSL_TLSEXT_ERR_NOACK;

+rc = init_dh(ctx_sni, cbinfo->dhparam, NULL);
+if (rc != OK) return SSL_TLSEXT_ERR_NOACK;
+
DEBUG(D_tls) debug_printf("Switching SSL context.\n");
SSL_set_SSL_CTX(s, ctx_sni);

@@ -779,7 +807,7 @@ else

/* Initialize with DH parameters if supplied */

-if (!init_dh(dhparam, host)) return DEFER;
+if (!init_dh(ctx, dhparam, host)) return DEFER;

/* Set up certificate and key (and perhaps OCSP info) */

diff --git a/src/util/gen_pkcs3.c b/src/util/gen_pkcs3.c
new file mode 100644
index 0000000..ae7e761
--- /dev/null
+++ b/src/util/gen_pkcs3.c
@@ -0,0 +1,229 @@
+/* Copyright (C) 2012 Phil Pennock.
+ * This is distributed as part of Exim and licensed under the GPL.
+ * See the file "NOTICE" for more details.
+ */
+
+/* Build with:
+ * c99 $(pkg-config --cflags openssl) gen_pkcs3.c $(pkg-config --libs openssl)
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+
+extern const char *__progname;
+
+
+void __attribute__((__noreturn__)) __attribute__((__format__(printf, 1, 2)))
+die(const char *fmt, ...)
+{
+  va_list ap;
+
+  fflush(NULL);
+  fprintf(stderr, "%s: ", __progname);
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+  fprintf(stderr, "\n");
+  fflush(stderr);
+  exit(1);
+}
+
+
+void __attribute__((__noreturn__))
+die_openssl_err(const char *msg)
+{
+  char err_string[250];
+  unsigned long e;
+
+  ERR_error_string_n(ERR_get_error(), err_string, sizeof(err_string));
+  die("%s: %s", msg, err_string);
+}
+
+
+static BIGNUM *
+bn_from_text(const char *text)
+{
+  BIGNUM *b;
+  char *p, *spaceless;
+  const char *q, *end;
+  size_t len;
+  int rc;
+
+  len = strlen(text);
+  spaceless = malloc(len);
+  if (!spaceless)
+    die("malloc(%zu) failed: %s", len, strerror(errno));
+
+  for (p = spaceless, q = text, end = text + len;
+       q < end;
+       ++q) {
+    if (!isspace(*q))
+      *p++ = *q;
+  }
+
+  b = NULL;
+  rc = BN_hex2bn(&b, spaceless);
+
+  if (rc != p - spaceless)
+    die("BN_hex2bn did not convert entire input; took %d of %z bytes",
+        rc, p - spaceless);
+
+  return b;
+}
+
+
+static void
+our_dh_check(DH *dh)
+{
+  int rc, errflags = 0;
+
+  rc = DH_check(dh, &errflags);
+  if (!rc) die_openssl_err("DH_check() could not be performed");;
+
+  /* We ignore DH_UNABLE_TO_CHECK_GENERATOR because some of the invocations
+   * deliberately provide generators other than 2 or 5. */
+
+  if (errflags & DH_CHECK_P_NOT_SAFE_PRIME)
+    die("DH_check(): p not a safe prime");
+  if (errflags & DH_NOT_SUITABLE_GENERATOR)
+    die("DH_check(): g not suitable as generator");
+}
+
+
+static void
+emit_c_format_dh(FILE *stream, DH *dh)
+{
+  BIO *bio;
+  long length;
+  char *data, *end, *p, *nl;
+
+  bio = BIO_new(BIO_s_mem());
+  PEM_write_bio_DHparams(bio, dh);
+  length = BIO_get_mem_data(bio, &data);
+  if (!length)
+    die("no data in memory BIO to format for printing");
+  if (length < 0)
+    die("grr, negative length memory not supported");
+  end = data + length;
+
+  for (p = data; p < end; /**/) {
+    nl = strchr(p, '\n');
+    if (!nl) {
+      fprintf(stream, "\"%s\\n\"\n/* missing final newline */\n", p);
+      break;
+    }
+    *nl = '\0';
+    fprintf(stream, "\"%s\\n\"\n", p);
+    p = nl + 1;
+  }
+}
+
+
+void __attribute__((__noreturn__))
+usage(FILE *stream, int exitcode)
+{
+  fprintf(stream, "Usage: %s [-CPcst] <dh_p> <dh_g>\n"
+"Both dh_p and dh_g should be hex strings representing the numbers\n"
+"They may contain whitespace.\n"
+"\n"
+" -C      show C string form of PEM result\n"
+" -P      do not show PEM\n"
+" -c      run OpenSSL DH_check() on the DH object\n"
+" -s      show the parsed p and g\n"
+" -t      show text form of certificate\n"
+
+      , __progname);
+  exit(exitcode);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+  BIGNUM *p, *g;
+  DH *dh;
+  int ch;
+  bool perform_dh_check = false;
+  bool show_c_form = false;
+  bool show_numbers = false;
+  bool show_pem = true;
+  bool show_text = false;
+
+  while ((ch = getopt(argc, argv, "CPcsth")) != -1) {
+    switch (ch) {
+      case 'C':
+        show_c_form = true;
+        break;
+      case 'P':
+        show_pem = false;
+        break;
+      case 'c':
+        perform_dh_check = true;
+        break;
+      case 's':
+        show_numbers = true;
+        break;
+      case 't':
+        show_text = true;
+        break;
+
+      case 'h':
+        usage(stdout, 0);
+      case '?':
+        die("Unknown option or missing argument -%c", optopt);
+      default:
+        die("Unhandled option -%c", ch);
+    }
+  }
+
+  optind -= 1;
+  argc -= optind;
+  argv += optind;
+
+  if (argc != 3) {
+    fprintf(stderr, "argc: %d\n", argc);
+    usage(stderr, 1);
+  }
+
+  p = bn_from_text(argv[1]);
+  g = bn_from_text(argv[2]);
+
+  if (show_numbers) {
+    printf("p = ");
+    BN_print_fp(stdout, p);
+    printf("\ng = ");
+    BN_print_fp(stdout, g);
+    printf("\n");
+  }
+
+  dh = DH_new();
+  dh->p = p;
+  dh->g = g;
+
+  if (perform_dh_check)
+    our_dh_check(dh);
+
+  if (show_text)
+    DHparams_print_fp(stdout, dh);
+
+  if (show_pem) {
+    if (show_c_form)
+      emit_c_format_dh(stdout, dh);
+    else
+      PEM_write_DHparams(stdout, dh);
+  }
+
+  DH_free(dh); /* should free p & g too */
+  return 0;
+}