Blob Blame Raw
Some servers have problem when connection uses TLS 1.0 or SSL 3.0.
Since openssl offers TLS 1.1 and 1.2, we would like to use these
when connecting to server, while having ability to disable these
protocols if needed.

https://bugzilla.redhat.com/show_bug.cgi?id=957840

Upstream related bug report:
http://dev.mutt.org/trac/ticket/3571

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