Verify that host matches certificate
When using https verify that the Common Name (CN) or the Subject Alternative Name listed in the server's certificate match the host we are connected to. Addresses LP bug 1079692. Change-Id: I24ea1511a2cbdb7c34ce72ac704d7b5e7d57cec2
This commit is contained in:
@@ -243,6 +243,8 @@ class VerifiedHTTPSConnection(httplib.HTTPSConnection):
|
||||
"""
|
||||
Extended HTTPSConnection which uses the OpenSSL library
|
||||
for enhanced SSL support.
|
||||
Note: Much of this functionality can eventually be replaced
|
||||
with native Python 3.3 code.
|
||||
"""
|
||||
def __init__(self, host, port, key_file=None, cert_file=None,
|
||||
ca_file=None, timeout=None, insecure=False,
|
||||
@@ -259,9 +261,47 @@ class VerifiedHTTPSConnection(httplib.HTTPSConnection):
|
||||
self.setcontext()
|
||||
|
||||
@staticmethod
|
||||
def verify_callback(connection, x509, errnum, errdepth, preverify_ok):
|
||||
# Pass through OpenSSL's default result
|
||||
return preverify_ok
|
||||
def host_matches_cert(host, x509):
|
||||
"""
|
||||
Verify that the the x509 certificate we have received
|
||||
from 'host' correctly identifies the server we are
|
||||
connecting to, ie that the certificate's Common Name
|
||||
or a Subject Alternative Name matches 'host'.
|
||||
"""
|
||||
# First see if we can match the CN
|
||||
if x509.get_subject().commonName == host:
|
||||
return True
|
||||
|
||||
# Also try Subject Alternative Names for a match
|
||||
san_list = None
|
||||
for i in xrange(x509.get_extension_count()):
|
||||
ext = x509.get_extension(i)
|
||||
if ext.get_short_name() == 'subjectAltName':
|
||||
san_list = str(ext)
|
||||
for san in ''.join(san_list.split()).split(','):
|
||||
if san == "DNS:%s" % host:
|
||||
return True
|
||||
|
||||
# Server certificate does not match host
|
||||
msg = ('Host "%s" does not match x509 certificate contents: '
|
||||
'CommonName "%s"' % (host, x509.get_subject().commonName))
|
||||
if san_list is not None:
|
||||
msg = msg + ', subjectAltName "%s"' % san_list
|
||||
raise exc.SSLCertificateError(msg)
|
||||
|
||||
def verify_callback(self, connection, x509, errnum,
|
||||
depth, preverify_ok):
|
||||
if x509.has_expired():
|
||||
msg = "SSL Certificate expired on '%s'" % x509.get_notAfter()
|
||||
raise exc.SSLCertificateError(msg)
|
||||
|
||||
if depth == 0 and preverify_ok is True:
|
||||
# We verify that the host matches against the last
|
||||
# certificate in the chain
|
||||
return self.host_matches_cert(self.host, x509)
|
||||
else:
|
||||
# Pass through OpenSSL's default result
|
||||
return preverify_ok
|
||||
|
||||
def setcontext(self):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user