Merge pull request #42 from ryanakca/next

Allow setting IMAP servers' SSL version
This commit is contained in:
xnox 2013-07-09 17:53:28 -07:00
commit e469a1e444
4 changed files with 35 additions and 6 deletions

View File

@ -325,6 +325,13 @@ ssl = yes
#cert_fingerprint = <SHA1_of_server_certificate_here> #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. # Specify the port. If not specified, use a default port.
# remoteport = 993 # remoteport = 993

View File

@ -39,7 +39,8 @@ Timeout handling further improved by Ethan Glasser-Camp <glasse@cs.rpi.edu> Dece
Time2Internaldate() patch to match RFC2060 specification of English month names from bugs.python.org/issue11024 March 2011. Time2Internaldate() patch to match RFC2060 specification of English month names from bugs.python.org/issue11024 March 2011.
starttls() bug fixed with the help of Sebastian Spaeth <sebastian@sspaeth.de> April 2011. starttls() bug fixed with the help of Sebastian Spaeth <sebastian@sspaeth.de> April 2011.
Threads now set the "daemon" flag (suggested by offlineimap-project) April 2011. Threads now set the "daemon" flag (suggested by offlineimap-project) April 2011.
Single quoting introduced with the help of Vladimir Marek <vladimir.marek@oracle.com> August 2011.""" Single quoting introduced with the help of Vladimir Marek <vladimir.marek@oracle.com> August 2011.
Support for specifying SSL version by Ryan Kavanagh <rak@debian.org> July 2013."""
__author__ = "Piers Lauder <piers@janeelix.com>" __author__ = "Piers Lauder <piers@janeelix.com>"
__URL__ = "http://imaplib2.sourceforge.net" __URL__ = "http://imaplib2.sourceforge.net"
__license__ = "Python License" __license__ = "Python License"
@ -460,7 +461,20 @@ class IMAP4(object):
cert_reqs = ssl.CERT_REQUIRED cert_reqs = ssl.CERT_REQUIRED
else: else:
cert_reqs = ssl.CERT_NONE 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" or self.ssl_version is None:
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 ssl_exc = ssl.SSLError
self.read_fd = self.sock.fileno() self.read_fd = self.sock.fileno()
except ImportError: except ImportError:
@ -1040,8 +1054,8 @@ class IMAP4(object):
return self._simple_command(name, sort_criteria, charset, *search_criteria, **kw) 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): 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) """(typ, [data]) = starttls(keyfile=None, certfile=None, ca_certs=None, cert_verify_cb=None, ssl_version="ssl23")
Start TLS negotiation as per RFC 2595.""" Start TLS negotiation as per RFC 2595."""
name = 'STARTTLS' name = 'STARTTLS'
@ -1076,6 +1090,7 @@ class IMAP4(object):
self.certfile = certfile self.certfile = certfile
self.ca_certs = ca_certs self.ca_certs = ca_certs
self.cert_verify_cb = cert_verify_cb self.cert_verify_cb = cert_verify_cb
self.ssl_version = ssl_version
try: try:
self.ssl_wrap_socket() self.ssl_wrap_socket()
@ -1972,7 +1987,7 @@ class IMAP4_SSL(IMAP4):
"""IMAP4 client class over SSL connection """IMAP4 client class over SSL connection
Instantiate with: 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); host - host's name (default: localhost);
port - port number (default: standard IMAP4 SSL port); port - port number (default: standard IMAP4 SSL port);
@ -1980,6 +1995,7 @@ class IMAP4_SSL(IMAP4):
certfile - PEM formatted certificate chain file (default: None); certfile - PEM formatted certificate chain file (default: None);
ca_certs - PEM formatted certificate chain file used to validate server certificates (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); 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 - debug level (default: 0 - no debug);
debug_file - debug stream (default: sys.stderr); debug_file - debug stream (default: sys.stderr);
identifier - thread identifier prefix (default: host); identifier - thread identifier prefix (default: host);
@ -1990,11 +2006,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.keyfile = keyfile
self.certfile = certfile self.certfile = certfile
self.ca_certs = ca_certs self.ca_certs = ca_certs
self.cert_verify_cb = cert_verify_cb 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) IMAP4.__init__(self, host, port, debug, debug_file, identifier, timeout, debug_buf_lvl)

View File

@ -65,6 +65,7 @@ class IMAPServer:
self.sslclientcert = repos.getsslclientcert() self.sslclientcert = repos.getsslclientcert()
self.sslclientkey = repos.getsslclientkey() self.sslclientkey = repos.getsslclientkey()
self.sslcacertfile = repos.getsslcacertfile() self.sslcacertfile = repos.getsslcacertfile()
self.sslversion = repos.getsslversion()
if self.sslcacertfile is None: if self.sslcacertfile is None:
self.verifycert = None # disable cert verification self.verifycert = None # disable cert verification
self.delim = None self.delim = None
@ -211,6 +212,7 @@ class IMAPServer:
self.sslclientcert, self.sslclientcert,
self.sslcacertfile, self.sslcacertfile,
self.verifycert, self.verifycert,
self.sslversion,
timeout=socket.getdefaulttimeout(), timeout=socket.getdefaulttimeout(),
fingerprint=fingerprint fingerprint=fingerprint
) )

View File

@ -172,6 +172,9 @@ class IMAPRepository(BaseRepository):
% (self.name, cacertfile)) % (self.name, cacertfile))
return cacertfile return cacertfile
def getsslversion(self):
return self.getconf('ssl_version', None)
def get_ssl_fingerprint(self): def get_ssl_fingerprint(self):
return self.getconf('cert_fingerprint', None) return self.getconf('cert_fingerprint', None)