~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/http/_urllib2_wrappers.py

  • Committer: Ross Lagerwall
  • Date: 2012-08-07 06:32:51 UTC
  • mto: (6437.63.5 2.5)
  • mto: This revision was merged to the branch mainline in revision 6558.
  • Revision ID: rosslagerwall@gmail.com-20120807063251-x9p03ghg2ws8oqjc
Add bzrlib/locale to .bzrignore

bzrlib/locale is generated with ./setup.py build_mo which is in turn called
by ./setup.py build

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2013, 2016 Canonical Ltd
 
1
# Copyright (C) 2006-2012 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
56
56
import urllib2
57
57
import urlparse
58
58
import re
59
 
import ssl
60
59
import sys
61
60
import time
62
61
 
69
68
    osutils,
70
69
    trace,
71
70
    transport,
72
 
    ui,
73
71
    urlutils,
74
 
)
75
 
 
76
 
try:
77
 
    _ = (ssl.match_hostname, ssl.CertificateError)
78
 
except AttributeError:
79
 
    # Provide fallbacks for python < 2.7.9
80
 
    def match_hostname(cert, host):
81
 
        trace.warning(
82
 
            '%s cannot be verified, https certificates verification is only'
83
 
            ' available for python versions >= 2.7.9' % (host,))
84
 
    ssl.match_hostname = match_hostname
85
 
    ssl.CertificateError = ValueError
 
72
    )
 
73
lazy_import.lazy_import(globals(), """
 
74
import ssl
 
75
""")
86
76
 
87
77
 
88
78
# Note for packagers: if there is no package providing certs for your platform,
89
79
# the curl project produces http://curl.haxx.se/ca/cacert.pem weekly.
90
80
_ssl_ca_certs_known_locations = [
91
 
    u'/etc/ssl/certs/ca-certificates.crt',  # Ubuntu/debian/gentoo
92
 
    u'/etc/pki/tls/certs/ca-bundle.crt',  # Fedora/CentOS/RH
93
 
    u'/etc/ssl/ca-bundle.pem',  # OpenSuse
94
 
    u'/etc/ssl/cert.pem',  # OpenSuse
95
 
    u"/usr/local/share/certs/ca-root-nss.crt",  # FreeBSD
 
81
    u'/etc/ssl/certs/ca-certificates.crt', # Ubuntu/debian/gentoo
 
82
    u'/etc/pki/tls/certs/ca-bundle.crt', # Fedora/CentOS/RH
 
83
    u'/etc/ssl/ca-bundle.pem', # OpenSuse
 
84
    u'/etc/ssl/cert.pem', # OpenSuse
 
85
    u"/usr/local/share/certs/ca-root-nss.crt", # FreeBSD
96
86
    # XXX: Needs checking, can't trust the interweb ;) -- vila 2012-01-25
97
 
    u'/etc/openssl/certs/ca-certificates.crt',  # Solaris
98
 
]
99
 
 
100
 
 
 
87
    u'/etc/openssl/certs/ca-certificates.crt', # Solaris
 
88
    ]
101
89
def default_ca_certs():
102
90
    if sys.platform == 'win32':
103
91
        return os.path.join(os.path.dirname(sys.executable), u"cacert.pem")
126
114
def cert_reqs_from_store(unicode_str):
127
115
    import ssl
128
116
    try:
129
 
        return {"required": ssl.CERT_REQUIRED,
130
 
                "none": ssl.CERT_NONE}[unicode_str]
 
117
        return {
 
118
            "required": ssl.CERT_REQUIRED,
 
119
            "none": ssl.CERT_NONE
 
120
            }[unicode_str]
131
121
    except KeyError:
132
122
        raise ValueError("invalid value %s" % unicode_str)
133
123
 
134
 
 
135
124
def default_ca_reqs():
136
125
    if sys.platform in ('win32', 'darwin'):
137
126
        # FIXME: Once we get a native access to root certificates there, this
141
130
        return u'required'
142
131
 
143
132
opt_ssl_ca_certs = config.Option('ssl.ca_certs',
144
 
                                 from_unicode=ca_certs_from_store,
145
 
                                 default=default_ca_certs,
146
 
                                 invalid='warning',
147
 
                                 help="""\
 
133
        from_unicode=ca_certs_from_store,
 
134
        default=default_ca_certs,
 
135
        invalid='warning',
 
136
        help="""\
148
137
Path to certification authority certificates to trust.
149
138
 
150
139
This should be a valid path to a bundle containing all root Certificate
154
143
""")
155
144
 
156
145
opt_ssl_cert_reqs = config.Option('ssl.cert_reqs',
157
 
                                  default=default_ca_reqs,
158
 
                                  from_unicode=cert_reqs_from_store,
159
 
                                  invalid='error',
160
 
                                  help="""\
 
146
        default=default_ca_reqs,
 
147
        from_unicode=cert_reqs_from_store,
 
148
        invalid='error',
 
149
        help="""\
161
150
Whether to require a certificate from the remote side. (default:required)
162
151
 
163
152
Possible values:
408
397
        self._wrap_socket_for_reporting(self.sock)
409
398
 
410
399
 
 
400
# These two methods were imported from Python 3.2's ssl module
 
401
 
 
402
def _dnsname_to_pat(dn):
 
403
    pats = []
 
404
    for frag in dn.split(r'.'):
 
405
        if frag == '*':
 
406
            # When '*' is a fragment by itself, it matches a non-empty dotless
 
407
            # fragment.
 
408
            pats.append('[^.]+')
 
409
        else:
 
410
            # Otherwise, '*' matches any dotless fragment.
 
411
            frag = re.escape(frag)
 
412
            pats.append(frag.replace(r'\*', '[^.]*'))
 
413
    return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
 
414
 
 
415
 
 
416
def match_hostname(cert, hostname):
 
417
    """Verify that *cert* (in decoded format as returned by
 
418
    SSLSocket.getpeercert()) matches the *hostname*.  RFC 2818 rules
 
419
    are mostly followed, but IP addresses are not accepted for *hostname*.
 
420
 
 
421
    CertificateError is raised on failure. On success, the function
 
422
    returns nothing.
 
423
    """
 
424
    if not cert:
 
425
        raise ValueError("empty or no certificate")
 
426
    dnsnames = []
 
427
    san = cert.get('subjectAltName', ())
 
428
    for key, value in san:
 
429
        if key == 'DNS':
 
430
            if _dnsname_to_pat(value).match(hostname):
 
431
                return
 
432
            dnsnames.append(value)
 
433
    if not san:
 
434
        # The subject is only checked when subjectAltName is empty
 
435
        for sub in cert.get('subject', ()):
 
436
            for key, value in sub:
 
437
                # XXX according to RFC 2818, the most specific Common Name
 
438
                # must be used.
 
439
                if key == 'commonName':
 
440
                    if _dnsname_to_pat(value).match(hostname):
 
441
                        return
 
442
                    dnsnames.append(value)
 
443
    if len(dnsnames) > 1:
 
444
        raise errors.CertificateError(
 
445
            "hostname %r doesn't match either of %s"
 
446
            % (hostname, ', '.join(map(repr, dnsnames))))
 
447
    elif len(dnsnames) == 1:
 
448
        raise errors.CertificateError("hostname %r doesn't match %r" %
 
449
                                      (hostname, dnsnames[0]))
 
450
    else:
 
451
        raise errors.CertificateError("no appropriate commonName or "
 
452
            "subjectAltName fields were found")
 
453
 
 
454
 
411
455
class HTTPSConnection(AbstractHTTPConnection, httplib.HTTPSConnection):
412
456
 
413
457
    def __init__(self, host, port=None, key_file=None, cert_file=None,
437
481
        else:
438
482
            host = self.host
439
483
        if cert_reqs == ssl.CERT_NONE:
440
 
            ui.ui_factory.show_user_warning('not_checking_ssl_cert', host=host)
441
 
            ui.ui_factory.suppressed_warnings.add('not_checking_ssl_cert')
 
484
            trace.warning("Not checking SSL certificate for %s", host)
442
485
            ca_certs = None
443
486
        else:
444
487
            if self.ca_certs is None:
451
494
                    "'bzr help ssl.ca_certs' for more information on setting "
452
495
                    "trusted CAs.")
453
496
        try:
454
 
            ssl_sock = ssl.wrap_socket(
455
 
                self.sock, self.key_file, self.cert_file,
 
497
            ssl_sock = ssl.wrap_socket(self.sock, self.key_file, self.cert_file,
456
498
                cert_reqs=cert_reqs, ca_certs=ca_certs)
457
 
        except ssl.SSLError:
 
499
        except ssl.SSLError, e:
458
500
            trace.note(
459
501
                "\n"
460
502
                "See `bzr help ssl.ca_certs` for how to specify trusted CA"
464
506
            raise
465
507
        if cert_reqs == ssl.CERT_REQUIRED:
466
508
            peer_cert = ssl_sock.getpeercert()
467
 
            ssl.match_hostname(peer_cert, host)
 
509
            match_hostname(peer_cert, host)
468
510
 
469
511
        # Wrap the ssl socket before anybody use it
470
512
        self._wrap_socket_for_reporting(ssl_sock)
782
824
                    % (request, request.connection.sock.getsockname())
783
825
            response = connection.getresponse()
784
826
            convert_to_addinfourl = True
785
 
        except (ssl.SSLError, ssl.CertificateError):
 
827
        except (ssl.SSLError, errors.CertificateError):
786
828
            # Something is wrong with either the certificate or the hostname,
787
829
            # re-trying won't help
788
830
            raise