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