diff options
author | Phil Pennock <pdp@exim.org> | 2010-06-05 09:10:08 +0000 |
---|---|---|
committer | Phil Pennock <pdp@exim.org> | 2010-06-05 09:10:08 +0000 |
commit | 77bb000fa965b786ddb1085dd5af6c80c7d425b0 (patch) | |
tree | 8af1cc6f65b2ce7dfcb31c652c5899c93a2c9ad4 /src | |
parent | de56d7a1960dedef0bf39b92deceee807ab88dc7 (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
Diffstat (limited to 'src')
-rw-r--r-- | src/src/functions.h | 5 | ||||
-rw-r--r-- | src/src/globals.c | 3 | ||||
-rw-r--r-- | src/src/globals.h | 3 | ||||
-rw-r--r-- | src/src/readconf.c | 20 | ||||
-rw-r--r-- | src/src/tls-openssl.c | 227 |
5 files changed, 239 insertions, 19 deletions
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 */ |