__init__.py
Go to the documentation of this file.
00001 """The match_hostname() function from Python 3.3.3, essential when using SSL."""
00002 
00003 import re
00004 
00005 __version__ = '3.4.0.2'
00006 
00007 class CertificateError(ValueError):
00008     pass
00009 
00010 
00011 def _dnsname_match(dn, hostname, max_wildcards=1):
00012     """Matching according to RFC 6125, section 6.4.3
00013 
00014     http://tools.ietf.org/html/rfc6125#section-6.4.3
00015     """
00016     pats = []
00017     if not dn:
00018         return False
00019 
00020     # Ported from python3-syntax:
00021     # leftmost, *remainder = dn.split(r'.')
00022     parts = dn.split(r'.')
00023     leftmost = parts[0]
00024     remainder = parts[1:]
00025 
00026     wildcards = leftmost.count('*')
00027     if wildcards > max_wildcards:
00028         # Issue #17980: avoid denials of service by refusing more
00029         # than one wildcard per fragment.  A survey of established
00030         # policy among SSL implementations showed it to be a
00031         # reasonable choice.
00032         raise CertificateError(
00033             "too many wildcards in certificate DNS name: " + repr(dn))
00034 
00035     # speed up common case w/o wildcards
00036     if not wildcards:
00037         return dn.lower() == hostname.lower()
00038 
00039     # RFC 6125, section 6.4.3, subitem 1.
00040     # The client SHOULD NOT attempt to match a presented identifier in which
00041     # the wildcard character comprises a label other than the left-most label.
00042     if leftmost == '*':
00043         # When '*' is a fragment by itself, it matches a non-empty dotless
00044         # fragment.
00045         pats.append('[^.]+')
00046     elif leftmost.startswith('xn--') or hostname.startswith('xn--'):
00047         # RFC 6125, section 6.4.3, subitem 3.
00048         # The client SHOULD NOT attempt to match a presented identifier
00049         # where the wildcard character is embedded within an A-label or
00050         # U-label of an internationalized domain name.
00051         pats.append(re.escape(leftmost))
00052     else:
00053         # Otherwise, '*' matches any dotless string, e.g. www*
00054         pats.append(re.escape(leftmost).replace(r'\*', '[^.]*'))
00055 
00056     # add the remaining fragments, ignore any wildcards
00057     for frag in remainder:
00058         pats.append(re.escape(frag))
00059 
00060     pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
00061     return pat.match(hostname)
00062 
00063 
00064 def match_hostname(cert, hostname):
00065     """Verify that *cert* (in decoded format as returned by
00066     SSLSocket.getpeercert()) matches the *hostname*.  RFC 2818 and RFC 6125
00067     rules are followed, but IP addresses are not accepted for *hostname*.
00068 
00069     CertificateError is raised on failure. On success, the function
00070     returns nothing.
00071     """
00072     if not cert:
00073         raise ValueError("empty or no certificate")
00074     dnsnames = []
00075     san = cert.get('subjectAltName', ())
00076     for key, value in san:
00077         if key == 'DNS':
00078             if _dnsname_match(value, hostname):
00079                 return
00080             dnsnames.append(value)
00081     if not dnsnames:
00082         # The subject is only checked when there is no dNSName entry
00083         # in subjectAltName
00084         for sub in cert.get('subject', ()):
00085             for key, value in sub:
00086                 # XXX according to RFC 2818, the most specific Common Name
00087                 # must be used.
00088                 if key == 'commonName':
00089                     if _dnsname_match(value, hostname):
00090                         return
00091                     dnsnames.append(value)
00092     if len(dnsnames) > 1:
00093         raise CertificateError("hostname %r "
00094             "doesn't match either of %s"
00095             % (hostname, ', '.join(map(repr, dnsnames))))
00096     elif len(dnsnames) == 1:
00097         raise CertificateError("hostname %r "
00098             "doesn't match %r"
00099             % (hostname, dnsnames[0]))
00100     else:
00101         raise CertificateError("no appropriate commonName or "
00102             "subjectAltName fields were found")


rosbridge_server
Author(s): Jonathan Mace
autogenerated on Wed Sep 13 2017 03:18:20