Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / requests / packages / urllib3 / packages / ssl_match_hostname / _implementation.py @ 564

History | View | Annotate | Download (3.69 KB)

1
"""The match_hostname() function from Python 3.3.3, essential when using SSL."""
2

    
3
# Note: This file is under the PSF license as the code comes from the python
4
# stdlib.   http://docs.python.org/3/license.html
5

    
6
import re
7

    
8
__version__ = '3.4.0.2'
9

    
10
class CertificateError(ValueError):
11
    pass
12

    
13

    
14
def _dnsname_match(dn, hostname, max_wildcards=1):
15
    """Matching according to RFC 6125, section 6.4.3
16

17
    http://tools.ietf.org/html/rfc6125#section-6.4.3
18
    """
19
    pats = []
20
    if not dn:
21
        return False
22

    
23
    # Ported from python3-syntax:
24
    # leftmost, *remainder = dn.split(r'.')
25
    parts = dn.split(r'.')
26
    leftmost = parts[0]
27
    remainder = parts[1:]
28

    
29
    wildcards = leftmost.count('*')
30
    if wildcards > max_wildcards:
31
        # Issue #17980: avoid denials of service by refusing more
32
        # than one wildcard per fragment.  A survey of established
33
        # policy among SSL implementations showed it to be a
34
        # reasonable choice.
35
        raise CertificateError(
36
            "too many wildcards in certificate DNS name: " + repr(dn))
37

    
38
    # speed up common case w/o wildcards
39
    if not wildcards:
40
        return dn.lower() == hostname.lower()
41

    
42
    # RFC 6125, section 6.4.3, subitem 1.
43
    # The client SHOULD NOT attempt to match a presented identifier in which
44
    # the wildcard character comprises a label other than the left-most label.
45
    if leftmost == '*':
46
        # When '*' is a fragment by itself, it matches a non-empty dotless
47
        # fragment.
48
        pats.append('[^.]+')
49
    elif leftmost.startswith('xn--') or hostname.startswith('xn--'):
50
        # RFC 6125, section 6.4.3, subitem 3.
51
        # The client SHOULD NOT attempt to match a presented identifier
52
        # where the wildcard character is embedded within an A-label or
53
        # U-label of an internationalized domain name.
54
        pats.append(re.escape(leftmost))
55
    else:
56
        # Otherwise, '*' matches any dotless string, e.g. www*
57
        pats.append(re.escape(leftmost).replace(r'\*', '[^.]*'))
58

    
59
    # add the remaining fragments, ignore any wildcards
60
    for frag in remainder:
61
        pats.append(re.escape(frag))
62

    
63
    pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
64
    return pat.match(hostname)
65

    
66

    
67
def match_hostname(cert, hostname):
68
    """Verify that *cert* (in decoded format as returned by
69
    SSLSocket.getpeercert()) matches the *hostname*.  RFC 2818 and RFC 6125
70
    rules are followed, but IP addresses are not accepted for *hostname*.
71

72
    CertificateError is raised on failure. On success, the function
73
    returns nothing.
74
    """
75
    if not cert:
76
        raise ValueError("empty or no certificate")
77
    dnsnames = []
78
    san = cert.get('subjectAltName', ())
79
    for key, value in san:
80
        if key == 'DNS':
81
            if _dnsname_match(value, hostname):
82
                return
83
            dnsnames.append(value)
84
    if not dnsnames:
85
        # The subject is only checked when there is no dNSName entry
86
        # in subjectAltName
87
        for sub in cert.get('subject', ()):
88
            for key, value in sub:
89
                # XXX according to RFC 2818, the most specific Common Name
90
                # must be used.
91
                if key == 'commonName':
92
                    if _dnsname_match(value, hostname):
93
                        return
94
                    dnsnames.append(value)
95
    if len(dnsnames) > 1:
96
        raise CertificateError("hostname %r "
97
            "doesn't match either of %s"
98
            % (hostname, ', '.join(map(repr, dnsnames))))
99
    elif len(dnsnames) == 1:
100
        raise CertificateError("hostname %r "
101
            "doesn't match %r"
102
            % (hostname, dnsnames[0]))
103
    else:
104
        raise CertificateError("no appropriate commonName or "
105
            "subjectAltName fields were found")