398
398
self._wrap_socket_for_reporting(self.sock)
401
# These two methods were imported from Python 3.2's ssl module
403
def _dnsname_to_pat(dn, max_wildcards=1):
405
for frag in dn.split(r'.'):
406
if frag.count('*') > max_wildcards:
407
# Python Issue #17980: avoid denials of service by refusing more
408
# than one wildcard per fragment. A survery of established
409
# policy among SSL implementations showed it to be a
412
"too many wildcards in certificate DNS name: " + repr(dn))
414
# When '*' is a fragment by itself, it matches a non-empty dotless
418
# Otherwise, '*' matches any dotless fragment.
419
frag = re.escape(frag)
420
pats.append(frag.replace(r'\*', '[^.]*'))
421
return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
424
def match_hostname(cert, hostname):
425
"""Verify that *cert* (in decoded format as returned by
426
SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules
427
are mostly followed, but IP addresses are not accepted for *hostname*.
429
CertificateError is raised on failure. On success, the function
433
raise ValueError("empty or no certificate")
435
san = cert.get('subjectAltName', ())
436
for key, value in san:
438
if _dnsname_to_pat(value).match(hostname):
440
dnsnames.append(value)
442
# The subject is only checked when subjectAltName is empty
443
for sub in cert.get('subject', ()):
444
for key, value in sub:
445
# XXX according to RFC 2818, the most specific Common Name
447
if key == 'commonName':
448
if _dnsname_to_pat(value).match(hostname):
450
dnsnames.append(value)
451
if len(dnsnames) > 1:
452
raise errors.CertificateError(
453
"hostname %r doesn't match either of %s"
454
% (hostname, ', '.join(map(repr, dnsnames))))
455
elif len(dnsnames) == 1:
456
raise errors.CertificateError("hostname %r doesn't match %r" %
457
(hostname, dnsnames[0]))
459
raise errors.CertificateError("no appropriate commonName or "
460
"subjectAltName fields were found")
463
401
class HTTPSConnection(AbstractHTTPConnection, httplib.HTTPSConnection):
465
403
def __init__(self, host, port=None, key_file=None, cert_file=None,
516
454
if cert_reqs == ssl.CERT_REQUIRED:
517
455
peer_cert = ssl_sock.getpeercert()
518
match_hostname(peer_cert, host)
456
ssl.match_hostname(peer_cert, host)
520
458
# Wrap the ssl socket before anybody use it
521
459
self._wrap_socket_for_reporting(ssl_sock)
833
771
% (request, request.connection.sock.getsockname())
834
772
response = connection.getresponse()
835
773
convert_to_addinfourl = True
836
except (ssl.SSLError, errors.CertificateError):
774
except (ssl.SSLError, ssl.CertificateError):
837
775
# Something is wrong with either the certificate or the hostname,
838
776
# re-trying won't help