tls_dh_min_bits smtp transport option
authorPhil Pennock <pdp@exim.org>
Fri, 1 Jun 2012 09:52:31 +0000 (05:52 -0400)
committerPhil Pennock <pdp@exim.org>
Fri, 1 Jun 2012 09:52:31 +0000 (05:52 -0400)
Could not find an API for use with OpenSSL, so GnuTLS only

doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
doc/doc-txt/OptionLists.txt
src/src/buildconfig.c
src/src/config.h.defaults
src/src/functions.h
src/src/tls-gnu.c
src/src/tls-openssl.c
src/src/transports/smtp.c
src/src/transports/smtp.h

index 61cdc1ee16084f86740b025c2105e6944f0c1d5c..78d5b0b183041375c924889e53989a2097e632cf 100644 (file)
@@ -22451,6 +22451,19 @@ This option specifies a certificate revocation list. The expanded value must
 be the name of a file that contains a CRL in PEM format.
 
 
+.new
+.option tls_dh_min_bits smtp integer 1024
+.cindex "TLS" "Diffie-Hellman minimum acceptable size"
+When establishing a TLS session, if a ciphersuite which uses Diffie-Hellman
+key agreement is negotiated, the server will provide a large prime number
+for use.  This option establishes the minimum acceptable size of that number.
+If the parameter offered by the server is too small, then the TLS handshake
+will fail.
+
+Only supported when using GnuTLS.
+.wen
+
+
 .option tls_privatekey smtp string&!! unset
 .cindex "TLS" "client private key, location of"
 .vindex "&$host$&"
@@ -25004,6 +25017,13 @@ option).
 The &%tls_require_ciphers%& options operate differently, as described in the
 sections &<<SECTreqciphssl>>& and &<<SECTreqciphgnu>>&.
 .next
+.new
+The &%tls_dh_min_bits%& SMTP transport option is only honoured by GnuTLS.
+When using OpenSSL, this option is ignored.
+(If an API is found to let OpenSSL be configured in this way,
+let the Exim Maintainers know and we'll likely use it).
+.wen
+.next
 Some other recently added features may only be available in one or the other.
 This should be documented with the feature.  If the documentation does not
 explicitly state that the feature is infeasible in the other TLS
index 533ce5035b62cdc05d80d0a42821831082388356..635533fdab7ed6f1b960e4a527a5d82f3c39ee9a 100644 (file)
@@ -9,6 +9,9 @@ PP/01 Add -bI: framework, and -bI:sieve for querying sieve capabilities.
 PP/02 Make -n do something, by making it not do something.
       When combined with -bP, the name of an option is not output.
 
+PP/03 Added tls_dh_min_bits SMTP transport driver option, only honoured
+      by GnuTLS.
+
 
 Exim version 4.80
 -----------------
index 5088a24c496f3dc61e32a3c7d37ee31a5e837f24..be8285b679dfee4be5b269a86fee738b44fb7112 100644 (file)
@@ -20,6 +20,17 @@ Version 4.81
     For instance, "exim -n -bP pid_file_path" should just emit a pathname
     followed by a newline, and no other text.
 
+ 3. When built with SUPPORT_TLS and USE_GNUTLS, the SMTP transport driver now
+    has a "tls_dh_min_bits" option, to set the minimum acceptable number of
+    bits in the Diffie-Hellman prime offered by a server (in DH ciphersuites)
+    acceptable for security.  (Option accepted but ignored if using OpenSSL).
+    Defaults to 1024, the old value.  May be lowered only to 512, or raised as
+    far as you like.  Raising this may hinder TLS interoperability with other
+    sites and is not currently recommended.  Lowering this will permit you to
+    establish a TLS session which is not as secure as you might like.
+
+    Unless you really know what you are doing, leave it alone.
+
 
 Version 4.80
 ------------
index 45b7997d1723908809f4d11f7195daf154622780..b8e8599ed5a37e139fe70f170d97c017c4ed2d95 100644 (file)
@@ -548,6 +548,7 @@ tls_advertise_hosts                  host list       *             main
 tls_certificate                      string*         unset         main              3.20
                                                      unset         smtp              3.20
 tls_dh_max_bits                      integer         2236          main              4.80
+tls_dh_min_bits                      integer         1024          smtp              4.81
 tls_dhparam                          string*         unset         main              3.20
 tls_on_connect_ports                 string          unset         main              4.43
 tls_privatekey                       string*         unset         main              3.20
@@ -623,6 +624,7 @@ provide compatibility with Sendmail.
 -bh              Test incoming SMTP call, omitting callouts
 -bhc             Test incoming SMTP call, with callouts
 -bi            * Run <command>bi_command</command>
+-bI:help         Show list of accepted -bI:<tag> options
 -bm              Accept message on standard input
 -bmalware      + Invoke configured malware scanning against supplied filename
 -bnq             Don't qualify addresses in locally submitted messages
index 62114fc09ea2290f15316b56b82f82bbd3f7a894..f3390cb7513bfb91f9f3861811bbc28196ab4819 100644 (file)
@@ -847,16 +847,17 @@ else if (isgroup)
         }
 
       /* how many bits Exim, as a client, demands must be in D-H */
-      /* as of GnuTLS 2.12.x, we ask for "normal" for D-H PK; before that, we
-      specify the number of bits.  We've stuck with the historical value, but
-      it can be overridden. */
-      else if ((strcmp(name, "EXIM_CLIENT_DH_MIN_BITS") == 0) ||
+      /* 1024 is a historical figure; some sites actually use lower, so we
+      permit the value to be lowered "dangerously" low, but not "insanely"
+      low.  Though actually, 1024 is becoming "dangerous". */
+      else if ((strcmp(name, "EXIM_CLIENT_DH_MIN_MIN_BITS") == 0) ||
+               (strcmp(name, "EXIM_CLIENT_DH_DEFAULT_MIN_BITS") == 0) ||
                (strcmp(name, "EXIM_SERVER_DH_BITS_PRE2_12") == 0))
         {
         long nv;
         char *end;
         nv = strtol(value, &end, 10);
-        if (end != value && *end == '\0' && nv >= 1000 && nv < 50000)
+        if (end != value && *end == '\0' && nv >= 512 && nv < 500000)
           {
           fprintf(new, "%s\n", value);
           }
index 92a4cd348373f9deb014704bb882f01eaa459ead..f02aef12ce34fdb86f9919afb9a2357b8f8b7c7b 100644 (file)
@@ -49,7 +49,8 @@ it's a default value. */
 #define EXIMDB_LOCK_TIMEOUT          60
 #define EXIMDB_LOCKFILE_MODE       0640
 #define EXIMDB_MODE                0640
-#define EXIM_CLIENT_DH_MIN_BITS
+#define EXIM_CLIENT_DH_MIN_MIN_BITS         512
+#define EXIM_CLIENT_DH_DEFAULT_MIN_BITS    1024
 #define EXIM_GNUTLS_LIBRARY_LOG_LEVEL
 #define EXIM_SERVER_DH_BITS_PRE2_12
 #define EXIM_PERL
index fa9d5585ec87b51acb44e3332d9a4169afac93aa..2758a4aec9bc61aa107a29fa4c3c61f36f29da3b 100644 (file)
@@ -27,7 +27,7 @@ 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);
+                 int, int);
 extern void    tls_close(BOOL);
 extern int     tls_feof(void);
 extern int     tls_ferror(void);
index c8bf634bc1ab26492de58225acade282bd4db900..cf315b6d1e0ba5e970cbe5ebbad743b165c4bdf4 100644 (file)
@@ -1536,6 +1536,7 @@ Arguments:
   verify_certs      file for certificate verify
   verify_crl        CRL for verify
   require_ciphers   list of allowed ciphers or NULL
+  dh_min_bits       minimum number of bits acceptable in server's DH prime
   timeout           startup timeout
 
 Returns:            OK/DEFER/FAIL (because using common functions),
@@ -1547,7 +1548,7 @@ tls_client_start(int fd, host_item *host,
     address_item *addr ARG_UNUSED, uschar *dhparam ARG_UNUSED,
     uschar *certificate, uschar *privatekey, uschar *sni,
     uschar *verify_certs, uschar *verify_crl,
-    uschar *require_ciphers, int timeout)
+    uschar *require_ciphers, int dh_min_bits, int timeout)
 {
 int rc;
 const char *error;
@@ -1559,7 +1560,17 @@ rc = tls_init(host, certificate, privatekey,
     sni, verify_certs, verify_crl, require_ciphers, &state);
 if (rc != OK) return rc;
 
-gnutls_dh_set_prime_bits(state->session, EXIM_CLIENT_DH_MIN_BITS);
+if (dh_min_bits < EXIM_CLIENT_DH_MIN_MIN_BITS)
+  {
+  DEBUG(D_tls)
+    debug_printf("WARNING: tls_dh_min_bits far too low, clamping %d up to %d\n",
+        dh_min_bits, EXIM_CLIENT_DH_MIN_MIN_BITS);
+  dh_min_bits = EXIM_CLIENT_DH_MIN_MIN_BITS;
+  }
+
+DEBUG(D_tls) debug_printf("Setting D-H prime minimum acceptable bits to %d\n",
+    dh_min_bits);
+gnutls_dh_set_prime_bits(state->session, dh_min_bits);
 
 if (verify_certs == NULL)
   {
index 22c0730c39c1ed2de9f41d61f5e0c07e473050fe..fdcb95ef2d4588732e4f83c3f114bba387ded025 100644 (file)
@@ -1233,6 +1233,8 @@ Argument:
   verify_certs     file for certificate verify
   crl              file containing CRL
   require_ciphers  list of allowed ciphers
+  dh_min_bits      minimum number of bits acceptable in server's DH prime
+                   (unused in OpenSSL)
   timeout          startup timeout
 
 Returns:           OK on success
@@ -1244,7 +1246,7 @@ int
 tls_client_start(int fd, host_item *host, address_item *addr, uschar *dhparam,
   uschar *certificate, uschar *privatekey, uschar *sni,
   uschar *verify_certs, uschar *crl,
-  uschar *require_ciphers, int timeout)
+  uschar *require_ciphers, int dh_min_bits ARG_UNUSED, int timeout)
 {
 static uschar txt[256];
 uschar *expciphers;
index f9f225fca341fa84afffc914e9acee62823c988a..b3856f5538de5ddd6bd5a2f4ff993b0e009c2bc5 100644 (file)
@@ -129,6 +129,8 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, tls_certificate) },
   { "tls_crl",              opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_crl) },
+  { "tls_dh_min_bits",      opt_int,
+      (void *)offsetof(smtp_transport_options_block, tls_dh_min_bits) },
   { "tls_privatekey",       opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, tls_privatekey) },
   { "tls_require_ciphers",  opt_stringptr,
@@ -195,9 +197,11 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* gnutls_require_kx */
   NULL,                /* gnutls_require_mac */
   NULL,                /* gnutls_require_proto */
+  NULL,                /* tls_sni */
   NULL,                /* tls_verify_certificates */
-  TRUE,                /* tls_tempfail_tryclear */
-  NULL                 /* tls_sni */
+  EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
+                       /* tls_dh_min_bits */
+  TRUE                 /* tls_tempfail_tryclear */
 #endif
 #ifndef DISABLE_DKIM
  ,NULL,                /* dkim_canon */
@@ -1136,6 +1140,7 @@ if (tls_offered && !suppress_tls &&
       ob->tls_verify_certificates,
       ob->tls_crl,
       ob->tls_require_ciphers,
+      ob->tls_dh_min_bits,
       ob->command_timeout);
 
     /* TLS negotiation failed; give an error. From outside, this function may
index 621cb6ba9ee451c83f23024a4ec6196db897ac46..17b75cf3b6694cad07f9bb47504c1f219a6f8c2c 100644 (file)
@@ -52,9 +52,10 @@ typedef struct {
   uschar *gnutls_require_kx;
   uschar *gnutls_require_mac;
   uschar *gnutls_require_proto;
+  uschar *tls_sni;
   uschar *tls_verify_certificates;
+  int     tls_dh_min_bits;
   BOOL    tls_tempfail_tryclear;
-  uschar *tls_sni;
   #endif
   #ifndef DISABLE_DKIM
   uschar *dkim_domain;