From 54c90be16587ca315041c964e251f07fc2bcf0e9 Mon Sep 17 00:00:00 2001 From: Phil Pennock Date: Fri, 1 Jun 2012 05:52:31 -0400 Subject: [PATCH] tls_dh_min_bits smtp transport option Could not find an API for use with OpenSSL, so GnuTLS only --- doc/doc-docbook/spec.xfpt | 20 ++++++++++++++++++++ doc/doc-txt/ChangeLog | 3 +++ doc/doc-txt/NewStuff | 11 +++++++++++ doc/doc-txt/OptionLists.txt | 2 ++ src/src/buildconfig.c | 11 ++++++----- src/src/config.h.defaults | 3 ++- src/src/functions.h | 2 +- src/src/tls-gnu.c | 15 +++++++++++++-- src/src/tls-openssl.c | 4 +++- src/src/transports/smtp.c | 9 +++++++-- src/src/transports/smtp.h | 3 ++- 11 files changed, 70 insertions(+), 13 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 61cdc1ee1..78d5b0b18 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -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 &<>& and &<>&. .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 diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 533ce5035..635533fda 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -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 ----------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 5088a24c4..be8285b67 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -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 ------------ diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt index 45b7997d1..b8e8599ed 100644 --- a/doc/doc-txt/OptionLists.txt +++ b/doc/doc-txt/OptionLists.txt @@ -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 bi_command +-bI:help Show list of accepted -bI: options -bm Accept message on standard input -bmalware + Invoke configured malware scanning against supplied filename -bnq Don't qualify addresses in locally submitted messages diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c index 62114fc09..f3390cb75 100644 --- a/src/src/buildconfig.c +++ b/src/src/buildconfig.c @@ -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); } diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index 92a4cd348..f02aef12c 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -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 diff --git a/src/src/functions.h b/src/src/functions.h index fa9d5585e..2758a4aec 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -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); diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index c8bf634bc..cf315b6d1 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -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) { diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 22c0730c3..fdcb95ef2 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -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; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index f9f225fca..b3856f553 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -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 diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index 621cb6ba9..17b75cf3b 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -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; -- 2.25.1