summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Pennock <pdp@exim.org>2010-06-05 09:10:08 +0000
committerPhil Pennock <pdp@exim.org>2010-06-05 09:10:08 +0000
commit77bb000fa965b786ddb1085dd5af6c80c7d425b0 (patch)
tree8af1cc6f65b2ce7dfcb31c652c5899c93a2c9ad4
parentde56d7a1960dedef0bf39b92deceee807ab88dc7 (diff)
Add an openssl_options main configuration option, to allow administrators to
shoot themselves in each foot in turn. The default value is chosen to avoid a change in behaviour, but since it is disabling a security countermeasure, I'd like to change the default to be "no options". Fixes: #994
-rw-r--r--doc/doc-docbook/spec.xfpt33
-rw-r--r--doc/doc-txt/ChangeLog4
-rw-r--r--doc/doc-txt/NewStuff14
-rw-r--r--src/src/functions.h5
-rw-r--r--src/src/globals.c3
-rw-r--r--src/src/globals.h3
-rw-r--r--src/src/readconf.c20
-rw-r--r--src/src/tls-openssl.c227
8 files changed, 287 insertions, 22 deletions
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index b33edeb97..493c55445 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -1,4 +1,4 @@
-. $Cambridge: exim/doc/doc-docbook/spec.xfpt,v 1.74 2010/05/29 19:26:31 nm4 Exp $
+. $Cambridge: exim/doc/doc-docbook/spec.xfpt,v 1.75 2010/06/05 09:10:08 pdp Exp $
.
. /////////////////////////////////////////////////////////////////////////////
. This is the primary source of the Exim Manual. It is an xfpt document that is
@@ -12392,6 +12392,7 @@ listed in more than one group.
.row &%gnutls_require_mac%& "control GnuTLS MAC algorithms"
.row &%gnutls_require_protocols%& "control GnuTLS protocols"
.row &%gnutls_compat_mode%& "use GnuTLS compatibility mode"
+.row &%openssl_options%& "adjust OpenSSL compatibility options"
.row &%tls_advertise_hosts%& "advertise TLS to these hosts"
.row &%tls_certificate%& "location of server certificate"
.row &%tls_crl%& "certificate revocation list"
@@ -14003,6 +14004,36 @@ harm. This option overrides the &%pipe_as_creator%& option of the &(pipe)&
transport driver.
+.option openssl_options main "string list" +dont_insert_empty_fragments
+.cindex "OpenSSL "compatibility options"
+This option allows an administrator to adjust the SSL options applied
+by OpenSSL to connections. It is given as a space-separated list of items,
+each one to be +added or -subtracted from the current value. The default
+value is one option which happens to have been set historically. You can
+remove all options with:
+.code
+openssl_options = -all
+.endd
+This option is only available if Exim is built against OpenSSL. The values
+available for this option vary according to the age of your OpenSSL install.
+The &"all"& value controls a subset of flags which are available, typically
+the bug workaround options. The &'SSL_CTX_set_options'& man page will
+list the values known on your system and Exim should support all the
+&"bug workaround"& options and many of the &"modifying"& options. The Exim
+names lose the leading &"SSL_OP_"& and are lower-cased.
+
+Note that adjusting the options can have severe impact upon the security of
+SSL as used by Exim. It is possible to disable safety checks and shoot
+yourself in the foot in various unpleasant ways. This option should not be
+adjusted lightly. An unrecognised item will be detected at by invoking Exim
+with the &%-bV%& flag.
+
+An example:
+.code
+openssl_options = -all +microsoft_big_sslv3_buffer
+.endd
+
+
.option oracle_servers main "string list" unset
.cindex "Oracle" "server list"
This option provides a list of Oracle servers and associated connection data,
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 7b560e527..3ed3aa8c7 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.616 2010/06/03 15:20:41 jetmore Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.617 2010/06/05 09:10:09 pdp Exp $
Change log file for Exim from version 4.21
-------------------------------------------
@@ -14,6 +14,8 @@ PP/02 Include check_rfc2047_length in configure.default because we're seeing
JJ/01 Added DISABLE_DKIM and comment to src/EDITME
+PP/03 Bugzilla 994: added openssl_options main configuration option.
+
Exim version 4.72
-----------------
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index b42c0d07c..589bc5397 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/NewStuff,v 1.165 2010/06/03 15:20:41 jetmore Exp $
+$Cambridge: exim/doc/doc-txt/NewStuff,v 1.166 2010/06/05 09:10:09 pdp Exp $
New Features in Exim
--------------------
@@ -9,6 +9,18 @@ test from the snapshots or the CVS before the documentation is updated. Once
the documentation is updated, this file is reduced to a short list.
+Version 4.73
+------------
+
+ 1. A new main configuration option, "openssl_options", is available if Exim
+ is built with SSL support provided by OpenSSL. The option allows
+ administrators to specify OpenSSL options to be used on connections;
+ typically this is to set bug compatibility features which the OpenSSL
+ developers have not enabled by default. There may be security
+ consequences for certain options, so these should not be changed
+ frivolously.
+
+
Version 4.72
------------
diff --git a/src/src/functions.h b/src/src/functions.h
index 49bdbf3d8..612d1e708 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/functions.h,v 1.47 2009/11/16 19:50:37 nm4 Exp $ */
+/* $Cambridge: exim/src/src/functions.h,v 1.48 2010/06/05 09:10:10 pdp Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -36,6 +36,9 @@ extern BOOL tls_smtp_buffered(void);
extern int tls_ungetc(int);
extern int tls_write(const uschar *, size_t);
extern void tls_version_report(FILE *);
+#ifndef USE_GNUTLS
+extern BOOL tls_openssl_options_parse(uschar *, long *);
+#endif
#endif
diff --git a/src/src/globals.c b/src/src/globals.c
index 3e1e76cff..b4e24485c 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.c,v 1.86 2009/11/16 19:50:37 nm4 Exp $ */
+/* $Cambridge: exim/src/src/globals.c,v 1.87 2010/06/05 09:10:10 pdp Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -115,6 +115,7 @@ BOOL gnutls_compat_mode = FALSE;
uschar *gnutls_require_mac = NULL;
uschar *gnutls_require_kx = NULL;
uschar *gnutls_require_proto = NULL;
+uschar *openssl_options = NULL;
const pcre *regex_STARTTLS = NULL;
uschar *tls_advertise_hosts = NULL; /* This is deliberate */
uschar *tls_certificate = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index cc5d601a5..e3991dcbd 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/globals.h,v 1.67 2009/11/16 19:50:37 nm4 Exp $ */
+/* $Cambridge: exim/src/src/globals.h,v 1.68 2010/06/05 09:10:10 pdp Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -75,6 +75,7 @@ extern BOOL gnutls_compat_mode; /* Less security, more compatibility */
extern uschar *gnutls_require_mac; /* So some can be avoided */
extern uschar *gnutls_require_kx; /* So some can be avoided */
extern uschar *gnutls_require_proto; /* So some can be avoided */
+extern uschar *openssl_options; /* OpenSSL compatibility options */
extern const pcre *regex_STARTTLS; /* For recognizing STARTTLS settings */
extern uschar *tls_advertise_hosts; /* host for which TLS is advertised */
extern uschar *tls_certificate; /* Certificate file */
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 41fb9f796..adb62205d 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/readconf.c,v 1.39 2009/11/16 19:50:37 nm4 Exp $ */
+/* $Cambridge: exim/src/src/readconf.c,v 1.40 2010/06/05 09:10:10 pdp Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -291,6 +291,9 @@ static optionlist optionlist_config[] = {
{ "mysql_servers", opt_stringptr, &mysql_servers },
#endif
{ "never_users", opt_uidlist, &never_users },
+#ifdef SUPPORT_TLS
+ { "openssl_options", opt_stringptr, &openssl_options },
+#endif
#ifdef LOOKUP_ORACLE
{ "oracle_servers", opt_stringptr, &oracle_servers },
#endif
@@ -2748,6 +2751,7 @@ void
readconf_main(void)
{
int sep = 0;
+long dummy_l;
struct stat statbuf;
uschar *s, *filename;
uschar *list = config_main_filelist;
@@ -3156,6 +3160,20 @@ if ((tls_verify_hosts != NULL || tls_try_verify_hosts != NULL) &&
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"tls_%sverify_hosts is set, but tls_verify_certificates is not set",
(tls_verify_hosts != NULL)? "" : "try_");
+
+/* If openssl_options is set, validate it */
+if (openssl_options != NULL)
+ {
+# ifdef USE_GNUTLS
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+ "openssl_options is set but we're using GnuTLS\n");
+# else
+ long dummy;
+ if (!(tls_openssl_options_parse(openssl_options, &dummy)))
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+ "openssl_options parse error: %s\n", openssl_options);
+# endif
+ }
#endif
}
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index a9251c7f4..a7dad0805 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/tls-openssl.c,v 1.22 2009/11/16 19:50:37 nm4 Exp $ */
+/* $Cambridge: exim/src/src/tls-openssl.c,v 1.23 2010/06/05 09:10:10 pdp Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -302,11 +302,14 @@ static int
tls_init(host_item *host, uschar *dhparam, uschar *certificate,
uschar *privatekey, address_item *addr)
{
+long init_options;
+BOOL okay;
+
SSL_load_error_strings(); /* basic set up */
OpenSSL_add_ssl_algorithms();
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-/* SHA256 is becoming ever moar popular. This makes sure it gets added to the
+/* SHA256 is becoming ever more popular. This makes sure it gets added to the
list of available digests. */
EVP_add_digest(EVP_sha256());
#endif
@@ -346,21 +349,28 @@ level. */
SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
-/* The following patch was supplied by Robert Roselius */
+/* Apply administrator-supplied work-arounds.
+Historically we applied just one requested option,
+SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS, but when bug 994 requested a second, we
+moved to an administrator-controlled list of options to specify and
+grandfathered in the first one as the default value for "openssl_options".
-#if OPENSSL_VERSION_NUMBER > 0x00906040L
-/* Enable client-bug workaround.
- Versions of OpenSSL as of 0.9.6d include a "CBC countermeasure" feature,
- which causes problems with some clients (such as the Certicom SSL Plus
- library used by Eudora). This option, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS,
- disables the coutermeasure allowing Eudora to connect.
- Some poppers and MTAs use SSL_OP_ALL, which enables all such bug
- workarounds. */
-/* XXX (Silently?) ignore failure here? XXX*/
+No OpenSSL version number checks: the options we accept depend upon the
+availability of the option value macros from OpenSSL. */
-if (!(SSL_CTX_set_options(ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)))
- return tls_error(US"SSL_CTX_set_option", host, NULL);
-#endif
+okay = tls_openssl_options_parse(openssl_options, &init_options);
+if (!okay)
+ return tls_error("openssl_options parsing failed", host, NULL);
+
+if (init_options)
+ {
+ DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options);
+ if (!(SSL_CTX_set_options(ctx, init_options)))
+ return tls_error(string_sprintf(
+ "SSL_CTX_set_option(%#lx)", init_options), host, NULL);
+ }
+else
+ DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
/* Initialize with DH parameters if supplied */
@@ -702,6 +712,9 @@ alarm(0);
if (rc <= 0)
{
tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL);
+ if (ERR_get_error() == 0)
+ log_write(0, LOG_MAIN,
+ " => client disconnected cleanly (rejected our certificate?)\n");
return FAIL;
}
@@ -1123,4 +1136,188 @@ smooth distribution and cares enough then they should submit a patch then. */
return r % max;
}
+
+
+
+/*************************************************
+* OpenSSL option parse *
+*************************************************/
+
+/* Parse one option for tls_openssl_options_parse below
+
+Arguments:
+ name one option name
+ value place to store a value for it
+Returns success or failure in parsing
+*/
+
+struct exim_openssl_option {
+ uschar *name;
+ long value;
+};
+/* We could use a macro to expand, but we need the ifdef and not all the
+options document which version they were introduced in. Policylet: include
+all options unless explicitly for DTLS, let the administrator choose which
+to apply.
+
+This list is current as of:
+ ==> 0.9.8n <== */
+static struct exim_openssl_option exim_openssl_options[] = {
+/* KEEP SORTED ALPHABETICALLY! */
+#ifdef SSL_OP_ALL
+ { "all", SSL_OP_ALL },
+#endif
+#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+ { "allow_unsafe_legacy_renegotiation", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION },
+#endif
+#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
+ { "cipher_server_preference", SSL_OP_CIPHER_SERVER_PREFERENCE },
+#endif
+#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+ { "dont_insert_empty_fragments", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS },
+#endif
+#ifdef SSL_OP_EPHEMERAL_RSA
+ { "ephemeral_rsa", SSL_OP_EPHEMERAL_RSA },
+#endif
+#ifdef SSL_OP_LEGACY_SERVER_CONNECT
+ { "legacy_server_connect", SSL_OP_LEGACY_SERVER_CONNECT },
+#endif
+#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
+ { "microsoft_big_sslv3_buffer", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER },
+#endif
+#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
+ { "microsoft_sess_id_bug", SSL_OP_MICROSOFT_SESS_ID_BUG },
+#endif
+#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
+ { "msie_sslv2_rsa_padding", SSL_OP_MSIE_SSLV2_RSA_PADDING },
+#endif
+#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
+ { "netscape_challenge_bug", SSL_OP_NETSCAPE_CHALLENGE_BUG },
+#endif
+#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+ { "netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG },
+#endif
+#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ { "no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION },
+#endif
+#ifdef SSL_OP_SINGLE_DH_USE
+ { "single_dh_use", SSL_OP_SINGLE_DH_USE },
+#endif
+#ifdef SSL_OP_SINGLE_ECDH_USE
+ { "single_ecdh_use", SSL_OP_SINGLE_ECDH_USE },
+#endif
+#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
+ { "ssleay_080_client_dh_bug", SSL_OP_SSLEAY_080_CLIENT_DH_BUG },
+#endif
+#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
+ { "sslref2_reuse_cert_type_bug", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG },
+#endif
+#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
+ { "tls_block_padding_bug", SSL_OP_TLS_BLOCK_PADDING_BUG },
+#endif
+#ifdef SSL_OP_TLS_D5_BUG
+ { "tls_d5_bug", SSL_OP_TLS_D5_BUG },
+#endif
+#ifdef SSL_OP_TLS_ROLLBACK_BUG
+ { "tls_rollback_bug", SSL_OP_TLS_ROLLBACK_BUG },
+#endif
+};
+static int exim_openssl_options_size =
+ sizeof(exim_openssl_options)/sizeof(struct exim_openssl_option);
+
+static BOOL
+tls_openssl_one_option_parse(uschar *name, long *value)
+{
+int first = 0;
+int last = exim_openssl_options_size;
+while (last > first)
+ {
+ int middle = (first + last)/2;
+ int c = Ustrcmp(name, exim_openssl_options[middle].name);
+ if (c == 0)
+ {
+ *value = exim_openssl_options[middle].value;
+ return TRUE;
+ }
+ else if (c > 0)
+ first = middle + 1;
+ else
+ last = middle;
+ }
+return FALSE;
+}
+
+
+
+
+/*************************************************
+* OpenSSL option parsing logic *
+*************************************************/
+
+/* OpenSSL has a number of compatibility options which an administrator might
+reasonably wish to set. Interpret a list similarly to decode_bits(), so that
+we look like log_selector.
+
+Arguments:
+ option_spec the administrator-supplied string of options
+ results ptr to long storage for the options bitmap
+Returns success or failure
+*/
+
+BOOL
+tls_openssl_options_parse(uschar *option_spec, long *results)
+{
+long result, item;
+uschar *s, *end;
+uschar keep_c;
+BOOL adding, item_parsed;
+
+/* We grandfather in as default the one option which we used to set always. */
+#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+result = SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+#else
+result = 0L;
+#endif
+
+if (option_spec == NULL)
+ {
+ *results = result;
+ return TRUE;
+ }
+
+for (s=option_spec; *s != '\0'; /**/)
+ {
+ while (isspace(*s)) ++s;
+ if (*s == '\0')
+ break;
+ if (*s != '+' && *s != '-')
+ {
+ DEBUG(D_tls) debug_printf("malformed openssl option setting: "
+ "+ or - expected but found \"%s\"", s);
+ return FALSE;
+ }
+ adding = *s++ == '+';
+ for (end = s; (*end != '\0') && !isspace(*end); ++end) /**/ ;
+ keep_c = *end;
+ *end = '\0';
+ item_parsed = tls_openssl_one_option_parse(s, &item);
+ if (!item_parsed)
+ {
+ DEBUG(D_tls) debug_printf("openssl option setting unrecognised: \"%s\"", s);
+ return FALSE;
+ }
+ DEBUG(D_tls) debug_printf("openssl option, %s from %lx: %lx (%s)\n",
+ adding ? "adding" : "removing", result, item, s);
+ if (adding)
+ result |= item;
+ else
+ result &= ~item;
+ *end = keep_c;
+ s = end;
+ }
+
+*results = result;
+return TRUE;
+}
+
/* End of tls-openssl.c */