openmedialibrary/oml/ssl_request.py

82 lines
3.3 KiB
Python
Raw Normal View History

2014-09-09 14:29:31 +00:00
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import ssl
2014-09-02 22:32:44 +00:00
import http.client
import urllib.request, urllib.error, urllib.parse
2014-05-14 09:57:11 +00:00
import hashlib
2014-05-17 14:26:59 +00:00
import logging
logger = logging.getLogger('oml.ssl_request')
2014-05-14 09:57:11 +00:00
2014-09-02 22:32:44 +00:00
class InvalidCertificateException(http.client.HTTPException, urllib.error.URLError):
2014-05-14 09:57:11 +00:00
def __init__(self, fingerprint, cert, reason):
2014-09-02 22:32:44 +00:00
http.client.HTTPException.__init__(self)
2014-09-09 14:29:31 +00:00
self._fingerprint = fingerprint
self._cert_fingerprint = hashlib.sha1(cert).hexdigest()
2014-05-14 09:57:11 +00:00
self.reason = reason
def __str__(self):
return ('%s (local) != %s (remote) (%s)\n' %
2014-09-09 14:29:31 +00:00
(self._fingerprint, self._cert_fingerprint, self.reason))
2014-05-14 09:57:11 +00:00
2014-09-09 14:29:31 +00:00
class FingerprintHTTPSConnection(http.client.HTTPSConnection):
2014-05-14 09:57:11 +00:00
def __init__(self, host, port=None, fingerprint=None, check_hostname=None, context=None, **kwargs):
2014-09-09 14:29:31 +00:00
self._fingerprint = fingerprint
if self._fingerprint:
check_hostname = False
# dont fial for older verions of python
# without ssl._create_default_https_context
# that also don't check by default
try:
context = ssl._create_default_https_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
except:
pass
2014-09-09 14:29:31 +00:00
http.client.HTTPSConnection.__init__(self, host, port,
check_hostname=check_hostname, context=context, **kwargs)
2014-05-14 09:57:11 +00:00
2014-09-09 14:29:31 +00:00
def _check_fingerprint(self, cert):
if len(self._fingerprint) == 40:
2014-09-05 23:44:17 +00:00
fingerprint = hashlib.sha1(cert).hexdigest()
2014-09-09 14:29:31 +00:00
elif len(self._fingerprint) == 64:
2014-09-05 23:44:17 +00:00
fingerprint = hashlib.sha256(cert).hexdigest()
2014-09-09 14:29:31 +00:00
elif len(self._fingerprint) == 128:
2014-09-05 23:44:17 +00:00
fingerprint = hashlib.sha512(cert).hexdigest()
else:
2014-09-09 14:29:31 +00:00
logging.error('unkown _fingerprint length %s (%s)',
self._fingerprint, len(self._fingerprint))
2014-09-05 23:44:17 +00:00
return False
logger.debug('ssl fingerprint: %s (match: %s)', fingerprint, fingerprint == self._fingerprint)
2015-02-27 10:49:56 +00:00
if fingerprint != self._fingerprint:
logger.debug('expected fingerprint: %s', self._fingerprint)
2014-09-09 14:29:31 +00:00
return fingerprint == self._fingerprint
2014-05-14 09:57:11 +00:00
def connect(self):
2014-09-09 14:29:31 +00:00
http.client.HTTPSConnection.connect(self)
if self._fingerprint:
2014-05-14 09:57:11 +00:00
cert = self.sock.getpeercert(binary_form=True)
2014-09-09 14:29:31 +00:00
if not self._check_fingerprint(cert):
raise InvalidCertificateException(self._fingerprint, cert,
2014-05-14 09:57:11 +00:00
'fingerprint mismatch')
2014-05-19 15:00:33 +00:00
#logger.debug('CIPHER %s VERSION %s', self.sock.cipher(), self.sock.ssl_version)
2014-05-14 09:57:11 +00:00
2014-09-09 14:29:31 +00:00
class FingerprintHTTPSHandler(urllib.request.HTTPSHandler):
2014-05-14 09:57:11 +00:00
2014-09-09 14:29:31 +00:00
def __init__(self, debuglevel=0, context=None, check_hostname=None, fingerprint=None):
urllib.request.AbstractHTTPHandler.__init__(self, debuglevel)
self._context = context
self._check_hostname = check_hostname
self._fingerprint = fingerprint
2014-05-14 09:57:11 +00:00
2014-09-09 14:29:31 +00:00
def https_open(self, req):
return self.do_open(FingerprintHTTPSConnection, req,
context=self._context, check_hostname=self._check_hostname,
fingerprint=self._fingerprint)
2014-05-14 09:57:11 +00:00
def get_opener(fingerprint):
2014-09-09 14:29:31 +00:00
handler = FingerprintHTTPSHandler(fingerprint=fingerprint)
2014-09-02 22:32:44 +00:00
opener = urllib.request.build_opener(handler)
2014-05-14 09:57:11 +00:00
return opener