e35c5e
Some servers have problem when connection uses TLS 1.0 or SSL 3.0.
e35c5e
Since openssl offers TLS 1.1 and 1.2, we would like to use these
e35c5e
when connecting to server, while having ability to disable these
e35c5e
protocols if needed.
e35c5e
e35c5e
https://bugzilla.redhat.com/show_bug.cgi?id=957840
e35c5e
e35c5e
Upstream related bug report:
e35c5e
http://dev.mutt.org/trac/ticket/3571
e35c5e
e35c5e
diff -up mutt-1.5.21/init.h.tlsv1v2 mutt-1.5.21/init.h
e35c5e
--- mutt-1.5.21/init.h.tlsv1v2	2013-06-27 12:46:14.120389035 +0200
e35c5e
+++ mutt-1.5.21/init.h	2013-06-27 12:47:28.020387743 +0200
e35c5e
@@ -2970,6 +2970,18 @@ struct option_t MuttVars[] = {
e35c5e
   ** This variable specifies whether to attempt to use TLSv1 in the
e35c5e
   ** SSL authentication process.
e35c5e
   */
e35c5e
+  { "ssl_use_tlsv1_1", DT_BOOL, R_NONE, OPTTLSV1_1, 1 },
e35c5e
+  /*
e35c5e
+  ** .pp
e35c5e
+  ** This variable specifies whether to attempt to use TLSv1.1 in the
e35c5e
+  ** SSL authentication process.
e35c5e
+  */
e35c5e
+  { "ssl_use_tlsv1_2", DT_BOOL, R_NONE, OPTTLSV1_2, 1 },
e35c5e
+  /*
e35c5e
+  ** .pp
e35c5e
+  ** This variable specifies whether to attempt to use TLSv1.2 in the
e35c5e
+  ** SSL authentication process.
e35c5e
+  */
e35c5e
 #ifdef USE_SSL_OPENSSL
e35c5e
   { "ssl_usesystemcerts", DT_BOOL, R_NONE, OPTSSLSYSTEMCERTS, 1 },
e35c5e
   /*
e35c5e
diff -up mutt-1.5.21/mutt.h.tlsv1v2 mutt-1.5.21/mutt.h
e35c5e
--- mutt-1.5.21/mutt.h.tlsv1v2	2010-09-13 19:19:55.000000000 +0200
e35c5e
+++ mutt-1.5.21/mutt.h	2013-06-27 12:47:28.020387743 +0200
e35c5e
@@ -376,6 +376,8 @@ enum
e35c5e
 # endif /* USE_SSL_GNUTLS */
e35c5e
   OPTSSLV3,
e35c5e
   OPTTLSV1,
e35c5e
+  OPTTLSV1_1,
e35c5e
+  OPTTLSV1_2,
e35c5e
   OPTSSLFORCETLS,
e35c5e
   OPTSSLVERIFYDATES,
e35c5e
   OPTSSLVERIFYHOST,
e35c5e
diff -up mutt-1.5.21/mutt_ssl.c.tlsv1v2 mutt-1.5.21/mutt_ssl.c
e35c5e
--- mutt-1.5.21/mutt_ssl.c.tlsv1v2	2010-08-25 18:31:40.000000000 +0200
e35c5e
+++ mutt-1.5.21/mutt_ssl.c	2013-06-27 12:47:28.021387743 +0200
e35c5e
@@ -106,6 +106,18 @@ int mutt_ssl_starttls (CONNECTION* conn)
e35c5e
     dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL_CTX\n"));
e35c5e
     goto bail_ssldata;
e35c5e
   }
e35c5e
+#ifdef SSL_OP_NO_TLSv1_1
e35c5e
+  if (!option(OPTTLSV1_1))
e35c5e
+  {
e35c5e
+    SSL_CTX_set_options(ssldata->ctx, SSL_OP_NO_TLSv1_1);
e35c5e
+  }
e35c5e
+#endif
e35c5e
+#ifdef SSL_OP_NO_TLSv1_2
e35c5e
+  if (!option(OPTTLSV1_2))
e35c5e
+  {
e35c5e
+    SSL_CTX_set_options(ssldata->ctx, SSL_OP_NO_TLSv1_2);
e35c5e
+  }
e35c5e
+#endif
e35c5e
 
e35c5e
   ssl_get_client_cert(ssldata, conn);
e35c5e
 
e35c5e
@@ -303,6 +315,21 @@ static int ssl_socket_open (CONNECTION *
e35c5e
   {
e35c5e
     SSL_CTX_set_options(data->ctx, SSL_OP_NO_TLSv1);
e35c5e
   }
e35c5e
+  /* TLSv1.1/1.2 support was added in OpenSSL 1.0.1, but some OS distros such
e35c5e
+   * as Fedora 17 are on OpenSSL 1.0.0.
e35c5e
+   */
e35c5e
+#ifdef SSL_OP_NO_TLSv1_1
e35c5e
+  if (!option(OPTTLSV1_1))
e35c5e
+  {
e35c5e
+    SSL_CTX_set_options(data->ctx, SSL_OP_NO_TLSv1_1);
e35c5e
+  }
e35c5e
+#endif
e35c5e
+#ifdef SSL_OP_NO_TLSv1_2
e35c5e
+  if (!option(OPTTLSV1_2))
e35c5e
+  {
e35c5e
+    SSL_CTX_set_options(data->ctx, SSL_OP_NO_TLSv1_2);
e35c5e
+  }
e35c5e
+#endif
e35c5e
   if (!option(OPTSSLV2))
e35c5e
   {
e35c5e
     SSL_CTX_set_options(data->ctx, SSL_OP_NO_SSLv2);
e35c5e
diff -up mutt-1.5.21/mutt_ssl_gnutls.c.tlsv1v2 mutt-1.5.21/mutt_ssl_gnutls.c
e35c5e
--- mutt-1.5.21/mutt_ssl_gnutls.c.tlsv1v2	2013-06-27 12:46:14.123389035 +0200
e35c5e
+++ mutt-1.5.21/mutt_ssl_gnutls.c	2013-06-27 12:47:28.018387743 +0200
e35c5e
@@ -238,7 +238,11 @@ err_crt:
e35c5e
   gnutls_x509_crt_deinit (clientcrt);
e35c5e
 }
e35c5e
 
e35c5e
-static int protocol_priority[] = {GNUTLS_TLS1, GNUTLS_SSL3, 0};
e35c5e
+/* This array needs to be large enough to hold all the possible values support
e35c5e
+ * by Mutt.  The initialized values are just placeholders--the array gets
e35c5e
+ * overwrriten in tls_negotiate() depending on the $ssl_use_* options.
e35c5e
+ */
e35c5e
+static int protocol_priority[] = {GNUTLS_TLS1_2, GNUTLS_TLS1_1, GNUTLS_TLS1, GNUTLS_SSL3, 0};
e35c5e
 
e35c5e
 /* tls_negotiate: After TLS state has been initialised, attempt to negotiate
e35c5e
  *   TLS over the wire, including certificate checks. */
e35c5e
@@ -246,6 +250,7 @@ static int tls_negotiate (CONNECTION * c
e35c5e
 {
e35c5e
   tlssockdata *data;
e35c5e
   int err;
e35c5e
+  size_t nproto = 0; /* number of tls/ssl protocols */
e35c5e
 
e35c5e
   data = (tlssockdata *) safe_calloc (1, sizeof (tlssockdata));
e35c5e
   conn->sockdata = data;
e35c5e
@@ -286,22 +291,22 @@ static int tls_negotiate (CONNECTION * c
e35c5e
   /* set socket */
e35c5e
   gnutls_transport_set_ptr (data->state, (gnutls_transport_ptr)conn->fd);
e35c5e
 
e35c5e
+  if (option(OPTTLSV1_2))
e35c5e
+    protocol_priority[nproto++] = GNUTLS_TLS1_2;
e35c5e
+  if (option(OPTTLSV1_1))
e35c5e
+    protocol_priority[nproto++] = GNUTLS_TLS1_1;
e35c5e
+  if (option(OPTTLSV1))
e35c5e
+    protocol_priority[nproto++] = GNUTLS_TLS1;
e35c5e
+  if (option(OPTSSLV3))
e35c5e
+    protocol_priority[nproto++] = GNUTLS_SSL3;
e35c5e
+  protocol_priority[nproto] = 0;
e35c5e
+
e35c5e
   /* disable TLS/SSL protocols as needed */
e35c5e
-  if (!option(OPTTLSV1) && !option(OPTSSLV3))
e35c5e
+  if (nproto == 0)
e35c5e
   {
e35c5e
     mutt_error (_("All available protocols for TLS/SSL connection disabled"));
e35c5e
     goto fail;
e35c5e
   }
e35c5e
-  else if (!option(OPTTLSV1))
e35c5e
-  {
e35c5e
-    protocol_priority[0] = GNUTLS_SSL3;
e35c5e
-    protocol_priority[1] = 0;
e35c5e
-  }
e35c5e
-  else if (!option(OPTSSLV3))
e35c5e
-  {
e35c5e
-    protocol_priority[0] = GNUTLS_TLS1;
e35c5e
-    protocol_priority[1] = 0;
e35c5e
-  }
e35c5e
   /*
e35c5e
   else
e35c5e
     use the list set above