tags 707252 + patch
thanks

The attached patch appears to fix the bug; I've forwarded[0] it
upstream.

Best wishes,
Ryan

[0] https://github.com/OfflineIMAP/offlineimap/pull/42

-- 
|_)|_/  Ryan Kavanagh           | Debian Developer
| \| \  http://ryanak.ca/       | GPG Key 4A11C97A
From 58ad7d238971d2f55089c37a5f2621e264cd3752 Mon Sep 17 00:00:00 2001
From: Ryan Kavanagh <r...@debian.org>
Date: Sun, 7 Jul 2013 17:18:59 -0400
Subject: [PATCH] Allow setting IMAP servers' SSL version

We now allow setting the SSL version used when connecting to IMAPS servers, and
do so via the `ssl_version` configuration option. We default to the current
practice (letting python's "ssl" library automatically detect the correct
version). There are however rare cases where one must specify the version to
use.

Signed-off-by: Ryan Kavanagh <r...@debian.org>
---
 offlineimap.conf               |  7 +++++++
 offlineimap/imaplib2.py        | 26 +++++++++++++++++++++-----
 offlineimap/imapserver.py      |  2 ++
 offlineimap/repository/IMAP.py |  3 +++
 4 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/offlineimap.conf b/offlineimap.conf
index fccceab..fabb52b 100644
--- a/offlineimap.conf
+++ b/offlineimap.conf
@@ -325,6 +325,13 @@ ssl = yes
 
 #cert_fingerprint = <SHA1_of_server_certificate_here>
 
+# SSL version (optional)
+# It is best to leave this unset, in which case the correct version will be
+# automatically detected. In rare cases, it may be necessary to specify a
+# particular version from: tls1, ssl2, ssl3, ssl23 (SSLv2 or SSLv3)
+
+# sslversion = ssl23
+
 # Specify the port.  If not specified, use a default port.
 # remoteport = 993
 
diff --git a/offlineimap/imaplib2.py b/offlineimap/imaplib2.py
index 8138d6c..2ad873a 100644
--- a/offlineimap/imaplib2.py
+++ b/offlineimap/imaplib2.py
@@ -460,7 +460,20 @@ class IMAP4(object):
                 cert_reqs = ssl.CERT_REQUIRED
             else:
                 cert_reqs = ssl.CERT_NONE
-            self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile, ca_certs=self.ca_certs, cert_reqs=cert_reqs)
+
+            if self.ssl_version == "tls1":
+                ssl_version = ssl.PROTOCOL_TLSv1
+            elif self.ssl_version == "ssl2":
+                ssl_version = ssl.PROTOCOL_SSLv2
+            elif self.ssl_version == "ssl3":
+                ssl_version = ssl.PROTOCOL_SSLv3
+            elif self.ssl_version == "ssl23":
+                ssl_version = ssl.PROTOCOL_SSLv23
+            else:
+                raise socket.sslerror("Invalid SSL version requested: %s",
+                        self.ssl_version)
+
+            self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile, ca_certs=self.ca_certs, cert_reqs=cert_reqs, ssl_version=ssl_version)
             ssl_exc = ssl.SSLError
             self.read_fd = self.sock.fileno()
         except ImportError:
@@ -1040,8 +1053,8 @@ class IMAP4(object):
         return self._simple_command(name, sort_criteria, charset, *search_criteria, **kw)
 
 
-    def starttls(self, keyfile=None, certfile=None, ca_certs=None, cert_verify_cb=None, **kw):
-        """(typ, [data]) = starttls(keyfile=None, certfile=None, ca_certs=None, cert_verify_cb=None)
+    def starttls(self, keyfile=None, certfile=None, ca_certs=None, cert_verify_cb=None, ssl_version="ssl23", **kw):
+        """(typ, [data]) = starttls(keyfile=None, certfile=None, ca_certs=None, cert_verify_cb=None, ssl_version="ssl23")
         Start TLS negotiation as per RFC 2595."""
 
         name = 'STARTTLS'
@@ -1076,6 +1089,7 @@ class IMAP4(object):
         self.certfile = certfile
         self.ca_certs = ca_certs
         self.cert_verify_cb = cert_verify_cb
+        self.ssl_version = ssl_version
 
         try:
             self.ssl_wrap_socket()
@@ -1972,7 +1986,7 @@ class IMAP4_SSL(IMAP4):
     """IMAP4 client class over SSL connection
 
     Instantiate with:
-        IMAP4_SSL(host=None, port=None, keyfile=None, certfile=None, debug=None, debug_file=None, identifier=None, timeout=None)
+        IMAP4_SSL(host=None, port=None, keyfile=None, certfile=None, ssl_version="ssl23", debug=None, debug_file=None, identifier=None, timeout=None)
 
         host           - host's name (default: localhost);
         port           - port number (default: standard IMAP4 SSL port);
@@ -1980,6 +1994,7 @@ class IMAP4_SSL(IMAP4):
         certfile       - PEM formatted certificate chain file (default: None);
         ca_certs       - PEM formatted certificate chain file used to validate server certificates (default: None);
         cert_verify_cb - function to verify authenticity of server certificates (default: None);
+        ssl_version    - SSL version to use (default: "ssl23", choose from: "tls1","ssl2","ssl3","ssl23");
         debug          - debug level (default: 0 - no debug);
         debug_file     - debug stream (default: sys.stderr);
         identifier     - thread identifier prefix (default: host);
@@ -1990,11 +2005,12 @@ class IMAP4_SSL(IMAP4):
     """
 
 
-    def __init__(self, host=None, port=None, keyfile=None, certfile=None, ca_certs=None, cert_verify_cb=None, debug=None, debug_file=None, identifier=None, timeout=None, debug_buf_lvl=None):
+    def __init__(self, host=None, port=None, keyfile=None, certfile=None, ca_certs=None, cert_verify_cb=None, ssl_version="ssl23", debug=None, debug_file=None, identifier=None, timeout=None, debug_buf_lvl=None):
         self.keyfile = keyfile
         self.certfile = certfile
         self.ca_certs = ca_certs
         self.cert_verify_cb = cert_verify_cb
+        self.ssl_version = ssl_version
         IMAP4.__init__(self, host, port, debug, debug_file, identifier, timeout, debug_buf_lvl)
 
 
diff --git a/offlineimap/imapserver.py b/offlineimap/imapserver.py
index 22c5c16..c8f70d6 100644
--- a/offlineimap/imapserver.py
+++ b/offlineimap/imapserver.py
@@ -65,6 +65,7 @@ class IMAPServer:
         self.sslclientcert = repos.getsslclientcert()
         self.sslclientkey = repos.getsslclientkey()
         self.sslcacertfile = repos.getsslcacertfile()
+        self.sslversion = repos.getsslversion()
         if self.sslcacertfile is None:
             self.verifycert = None # disable cert verification
         self.delim = None
@@ -211,6 +212,7 @@ class IMAPServer:
                                                            self.sslclientcert,
                                                            self.sslcacertfile,
                                                            self.verifycert,
+                                                           self.sslversion,
                                                            timeout=socket.getdefaulttimeout(),
                                                            fingerprint=fingerprint
                                                            )
diff --git a/offlineimap/repository/IMAP.py b/offlineimap/repository/IMAP.py
index be8c858..7ccabfa 100644
--- a/offlineimap/repository/IMAP.py
+++ b/offlineimap/repository/IMAP.py
@@ -172,6 +172,9 @@ class IMAPRepository(BaseRepository):
                                 % (self.name, cacertfile))
         return cacertfile
 
+    def getsslversion(self):
+        return self.getconf('ssl_version', None)
+
     def get_ssl_fingerprint(self):
         return self.getconf('cert_fingerprint', None)
 
-- 
1.8.3.2

Attachment: signature.asc
Description: Digital signature

Reply via email to