From c80c557026f3933b0472b13331924f8bd4ed9bf7 Mon Sep 17 00:00:00 2001 From: Phil Pennock Date: Sat, 28 Apr 2012 06:21:02 -0700 Subject: [PATCH] TLS fixes for OpenSSL. Support TLS 1.1 & 1.2 New "openssl_options" values (all now documented). Set SSL_MODE_AUTO_RETRY so that OpenSSL will retry a read or write after TLS renegotiation, which otherwise led to messages "Got SSL error 2". --- doc/doc-docbook/spec.xfpt | 55 +++++++++++++++++++++++++++++++++++++++ doc/doc-txt/ChangeLog | 5 ++++ src/README.UPDATING | 9 +++++++ src/src/tls-openssl.c | 45 +++++++++++++++++++++++++++----- 4 files changed, 107 insertions(+), 7 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index c1f845eaf..e719855f8 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -14362,6 +14362,61 @@ An example: openssl_options = -all +microsoft_big_sslv3_buffer .endd +Possible options may include: +.ilist +&`all`& +.ilist +&`allow_unsafe_legacy_renegotiation`& +.ilist +&`cipher_server_preference`& +.ilist +&`dont_insert_empty_fragments`& +.ilist +&`ephemeral_rsa`& +.ilist +&`legacy_server_connect`& +.ilist +&`microsoft_big_sslv3_buffer`& +.ilist +&`microsoft_sess_id_bug`& +.ilist +&`msie_sslv2_rsa_padding`& +.ilist +&`netscape_challenge_bug`& +.ilist +&`netscape_reuse_cipher_change_bug`& +.ilist +&`no_compression`& +.ilist +&`no_session_resumption_on_renegotiation`& +.ilist +&`no_sslv2`& +.ilist +&`no_sslv3`& +.ilist +&`no_ticket`& +.ilist +&`no_tlsv1`& +.ilist +&`no_tlsv1_1`& +.ilist +&`no_tlsv1_2`& +.ilist +&`single_dh_use`& +.ilist +&`single_ecdh_use`& +.ilist +&`ssleay_080_client_dh_bug`& +.ilist +&`sslref2_reuse_cert_type_bug`& +.ilist +&`tls_block_padding_bug`& +.ilist +&`tls_d5_bug`& +.ilist +&`tls_rollback_bug`& +.endlist + .option oracle_servers main "string list" unset .cindex "Oracle" "server list" diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 03f4469af..1d313879a 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -53,6 +53,11 @@ PP/13 tls_peerdn now print-escaped for spool files. Observed some $tls_peerdn in wild which contained \n, which resulted in spool file corruption. +PP/14 TLS fixes for OpenSSL: support TLS 1.1 & 1.2; new "openssl_options" + values; set SSL_MODE_AUTO_RETRY so that OpenSSL will retry a read + or write after TLS renegotiation, which otherwise led to messages + "Got SSL error 2". + Exim version 4.77 ----------------- diff --git a/src/README.UPDATING b/src/README.UPDATING index 1eb36277e..9e3689d84 100644 --- a/src/README.UPDATING +++ b/src/README.UPDATING @@ -39,6 +39,15 @@ Exim version 4.78 the message. No tool has been provided as we believe this is a rare occurence. + * With OpenSSL 1.0.1+, Exim now supports TLS 1.1 and TLS 1.2. If built + against 1.0.1a then you will get a warning message and the + "openssl_options" value will not parse "no_tlsv1_1": the value changes + incompatibly between 1.0.1a and 1.0.1b, because the value chosen for 1.0.1a + is infelicitous. We advise avoiding 1.0.1a. + + "openssl_options" gains "no_tlsv1_1", "no_tlsv1_2" and "no_compression". + + Exim version 4.77 ----------------- diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 2104711bb..e2e150c0a 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -347,6 +347,9 @@ level. */ SSL_CTX_set_info_callback(ctx, (void (*)())info_callback); +/* Automatically re-try reads/writes after renegotiation. */ +(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); + /* 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 @@ -456,6 +459,18 @@ switch (ssl->session->ssl_version) ver = US"TLSv1"; break; +#ifdef TLS1_1_VERSION + case TLS1_1_VERSION: + ver = US"TLSv1.1"; + break; +#endif + +#ifdef TLS1_2_VERSION + case TLS1_2_VERSION: + ver = US"TLSv1.2"; + break; +#endif + default: ver = US"UNKNOWN"; } @@ -873,8 +888,8 @@ if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm) int error; int inbytes; - DEBUG(D_tls) debug_printf("Calling SSL_read(%lx, %lx, %u)\n", (long)ssl, - (long)ssl_xfer_buffer, ssl_xfer_buffer_size); + DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl, + ssl_xfer_buffer, ssl_xfer_buffer_size); if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout); inbytes = SSL_read(ssl, CS ssl_xfer_buffer, ssl_xfer_buffer_size); @@ -920,6 +935,7 @@ if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm) ssl_xfer_error = 1; return EOF; } + #ifndef DISABLE_DKIM dkim_exim_verify_feed(ssl_xfer_buffer, inbytes); #endif @@ -953,8 +969,8 @@ tls_read(uschar *buff, size_t len) int inbytes; int error; -DEBUG(D_tls) debug_printf("Calling SSL_read(%lx, %lx, %u)\n", (long)ssl, - (long)buff, (unsigned int)len); +DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl, + buff, (unsigned int)len); inbytes = SSL_read(ssl, CS buff, len); error = SSL_get_error(ssl, inbytes); @@ -996,10 +1012,10 @@ int outbytes; int error; int left = len; -DEBUG(D_tls) debug_printf("tls_do_write(%lx, %d)\n", (long)buff, left); +DEBUG(D_tls) debug_printf("tls_do_write(%p, %d)\n", buff, left); while (left > 0) { - DEBUG(D_tls) debug_printf("SSL_write(SSL, %lx, %d)\n", (long)buff, left); + DEBUG(D_tls) debug_printf("SSL_write(SSL, %p, %d)\n", buff, left); outbytes = SSL_write(ssl, CS buff, left); error = SSL_get_error(ssl, outbytes); DEBUG(D_tls) debug_printf("outbytes=%d error=%d\n", outbytes, error); @@ -1177,7 +1193,7 @@ all options unless explicitly for DTLS, let the administrator choose which to apply. This list is current as of: - ==> 1.0.0c <== */ + ==> 1.0.1b <== */ static struct exim_openssl_option exim_openssl_options[] = { /* KEEP SORTED ALPHABETICALLY! */ #ifdef SSL_OP_ALL @@ -1213,6 +1229,9 @@ static struct exim_openssl_option exim_openssl_options[] = { #ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG { US"netscape_reuse_cipher_change_bug", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG }, #endif +#ifdef SSL_OP_NO_COMPRESSION + { US"no_compression", SSL_OP_NO_COMPRESSION }, +#endif #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION { US"no_session_resumption_on_renegotiation", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION }, #endif @@ -1228,6 +1247,17 @@ static struct exim_openssl_option exim_openssl_options[] = { #ifdef SSL_OP_NO_TLSv1 { US"no_tlsv1", SSL_OP_NO_TLSv1 }, #endif +#ifdef SSL_OP_NO_TLSv1_1 +#if SSL_OP_NO_TLSv1_1 == 0x00000400L + /* Error in chosen value in 1.0.1a; see first item in CHANGES for 1.0.1b */ +#warning OpenSSL 1.0.1a uses a bad value for SSL_OP_NO_TLSv1_1, ignoring +#else + { US"no_tlsv1_1", SSL_OP_NO_TLSv1_1 }, +#endif +#endif +#ifdef SSL_OP_NO_TLSv1_2 + { US"no_tlsv1_2", SSL_OP_NO_TLSv1_2 }, +#endif #ifdef SSL_OP_SINGLE_DH_USE { US"single_dh_use", SSL_OP_SINGLE_DH_USE }, #endif @@ -1253,6 +1283,7 @@ static struct exim_openssl_option exim_openssl_options[] = { 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) { -- 2.25.1