[PATCH] Implement Server SSL fingerprint check
Sebastian Spaeth
Sebastian at SSpaeth.de
Tue Aug 30 13:20:43 BST 2011
If we connect to a SSL server (not STARTTLS) and no CA cert has been
specified for verification, we check the configured SSL fingerprint and
bail out in case it has not been set yet, or it does not match.
This means one more mandatory option for SSL configuration, but it
improves security a lot.
Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
offlineimap/imaplibutil.py | 22 ++++++++++++++++++++--
offlineimap/imapserver.py | 2 ++
offlineimap/repository/IMAP.py | 3 +++
3 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/offlineimap/imaplibutil.py b/offlineimap/imaplibutil.py
index fa3a303..58e30ee 100644
--- a/offlineimap/imaplibutil.py
+++ b/offlineimap/imaplibutil.py
@@ -21,8 +21,10 @@ import re
import socket
import time
import subprocess
-from offlineimap.ui import getglobalui
import threading
+from hashlib import md5
+
+from offlineimap.ui import getglobalui
from offlineimap import OfflineImapError
from offlineimap.imaplib2 import IMAP4, IMAP4_SSL, zlib, IMAP4_PORT, InternalDate, Mon2num
@@ -130,7 +132,23 @@ def new_mesg(self, s, tn=None, secs=None):
class WrappedIMAP4_SSL(UsefulIMAPMixIn, IMAP4_SSL):
"""Improved version of imaplib.IMAP4_SSL overriding select()"""
- pass
+ def __init__(self, *args, **kwargs):
+ self._fingerprint = kwargs.get('fingerprint', None)
+ if kwargs.has_key('fingerprint'):
+ del kwargs['fingerprint']
+ super(WrappedIMAP4_SSL, self).__init__(*args, **kwargs)
+
+ def open(self, host=None, port=None):
+ super(WrappedIMAP4_SSL, self).open(host, port)
+ if not self.ca_certs:
+ # no CA certificate validation configured, check fingerprint
+ fingerprint = md5(self.sock.getpeercert(True)).hexdigest()
+ if fingerprint != self._fingerprint:
+ raise OfflineImapError("Server SSL fingerprint '%s' for hostnam"
+ "e '%s' does not match configured fingerprint. Please ver"
+ "ify and set 'sslfingerprint' accordingly if not set yet."
+ % (fingerprint, host),
+ OfflineImapError.ERROR.REPO)
class WrappedIMAP4(UsefulIMAPMixIn, IMAP4):
diff --git a/offlineimap/imapserver.py b/offlineimap/imapserver.py
index 3ce751c..523d838 100644
--- a/offlineimap/imapserver.py
+++ b/offlineimap/imapserver.py
@@ -206,6 +206,7 @@ class IMAPServer:
success = 1
elif self.usessl:
self.ui.connecting(self.hostname, self.port)
+ fingerprint = self.repos.get_ssl_fingerprint()
imapobj = imaplibutil.WrappedIMAP4_SSL(self.hostname,
self.port,
self.sslclientkey,
@@ -213,6 +214,7 @@ class IMAPServer:
self.sslcacertfile,
self.verifycert,
timeout=socket.getdefaulttimeout(),
+ fingerprint=fingerprint
)
else:
self.ui.connecting(self.hostname, self.port)
diff --git a/offlineimap/repository/IMAP.py b/offlineimap/repository/IMAP.py
index 68eb637..772bd3f 100644
--- a/offlineimap/repository/IMAP.py
+++ b/offlineimap/repository/IMAP.py
@@ -182,6 +182,9 @@ class IMAPRepository(BaseRepository):
% (self.name, cacertfile))
return cacertfile
+ def get_ssl_fingerprint(self):
+ return self.getconf('sslfingerprint', None)
+
def getpreauthtunnel(self):
return self.getconf('preauthtunnel', None)
--
1.7.4.1
More information about the OfflineIMAP-project
mailing list