78
_ = (ssl.match_hostname, ssl.CertificateError)
79
except AttributeError:
80
# Provide fallbacks for python < 2.7.9
81
def match_hostname(cert, host):
83
'%s cannot be verified, https certificates verification is only'
84
' available for python versions >= 2.7.9' % (host,))
85
ssl.match_hostname = match_hostname
86
ssl.CertificateError = ValueError
89
# Note for packagers: if there is no package providing certs for your platform,
90
# the curl project produces http://curl.haxx.se/ca/cacert.pem weekly.
91
_ssl_ca_certs_known_locations = [
92
u'/etc/ssl/certs/ca-certificates.crt', # Ubuntu/debian/gentoo
93
u'/etc/pki/tls/certs/ca-bundle.crt', # Fedora/CentOS/RH
94
u'/etc/ssl/ca-bundle.pem', # OpenSuse
95
u'/etc/ssl/cert.pem', # OpenSuse
96
u"/usr/local/share/certs/ca-root-nss.crt", # FreeBSD
97
# XXX: Needs checking, can't trust the interweb ;) -- vila 2012-01-25
98
u'/etc/openssl/certs/ca-certificates.crt', # Solaris
102
def default_ca_certs():
103
if sys.platform == 'win32':
104
return os.path.join(os.path.dirname(sys.executable), u"cacert.pem")
105
elif sys.platform == 'darwin':
106
# FIXME: Needs some default value for osx, waiting for osx installers
107
# guys feedback -- vila 2012-01-25
110
# Try known locations for friendly OSes providing the root certificates
111
# without making them hard to use for any https client.
112
for path in _ssl_ca_certs_known_locations:
113
if os.path.exists(path):
116
# A default path that makes sense and will be mentioned in the error
117
# presented to the user, even if not correct for all platforms
118
return _ssl_ca_certs_known_locations[0]
121
def ca_certs_from_store(path):
122
if not os.path.exists(path):
123
raise ValueError("ca certs path %s does not exist" % path)
127
def cert_reqs_from_store(unicode_str):
130
return {"required": ssl.CERT_REQUIRED,
131
"none": ssl.CERT_NONE}[unicode_str]
133
raise ValueError("invalid value %s" % unicode_str)
136
def default_ca_reqs():
137
if sys.platform in ('win32', 'darwin'):
138
# FIXME: Once we get a native access to root certificates there, this
139
# won't needed anymore. See http://pad.lv/920455 -- vila 2012-02-15
144
opt_ssl_ca_certs = config.Option('ssl.ca_certs',
145
from_unicode=ca_certs_from_store,
146
default=default_ca_certs,
149
Path to certification authority certificates to trust.
151
This should be a valid path to a bundle containing all root Certificate
152
Authorities used to verify an https server certificate.
154
Use ssl.cert_reqs=none to disable certificate verification.
157
opt_ssl_cert_reqs = config.Option('ssl.cert_reqs',
158
default=default_ca_reqs,
159
from_unicode=cert_reqs_from_store,
162
Whether to require a certificate from the remote side. (default:required)
165
* none: Certificates ignored
166
* required: Certificates required and validated
169
checked_kerberos = False
77
173
class addinfourl(urllib2.addinfourl):
300
396
# XXX: Needs refactoring at the caller level.
301
397
def __init__(self, host, port=None, proxied_host=None,
302
report_activity=None):
398
report_activity=None, ca_certs=None):
303
399
AbstractHTTPConnection.__init__(self, report_activity=report_activity)
304
400
# Use strict=True since we don't support HTTP/0.9
305
401
httplib.HTTPConnection.__init__(self, host, port, strict=True)
306
402
self.proxied_host = proxied_host
403
# ca_certs is ignored, it's only relevant for https
308
405
def connect(self):
309
406
if 'http' in debug.debug_flags:
312
409
self._wrap_socket_for_reporting(self.sock)
315
# Build the appropriate socket wrapper for ssl
317
# python 2.6 introduced a better ssl package
319
_ssl_wrap_socket = ssl.wrap_socket
321
# python versions prior to 2.6 don't have ssl and ssl.wrap_socket instead
322
# they use httplib.FakeSocket
323
def _ssl_wrap_socket(sock, key_file, cert_file):
324
ssl_sock = socket.ssl(sock, key_file, cert_file)
325
return httplib.FakeSocket(sock, ssl_sock)
328
412
class HTTPSConnection(AbstractHTTPConnection, httplib.HTTPSConnection):
330
414
def __init__(self, host, port=None, key_file=None, cert_file=None,
331
415
proxied_host=None,
332
report_activity=None):
416
report_activity=None, ca_certs=None):
333
417
AbstractHTTPConnection.__init__(self, report_activity=report_activity)
334
418
# Use strict=True since we don't support HTTP/0.9
335
419
httplib.HTTPSConnection.__init__(self, host, port,
336
420
key_file, cert_file, strict=True)
337
421
self.proxied_host = proxied_host
422
self.ca_certs = ca_certs
339
424
def connect(self):
340
425
if 'http' in debug.debug_flags:
345
430
self.connect_to_origin()
347
432
def connect_to_origin(self):
348
ssl_sock = _ssl_wrap_socket(self.sock, self.key_file, self.cert_file)
433
# FIXME JRV 2011-12-18: Use location config here?
434
config_stack = config.GlobalStack()
435
cert_reqs = config_stack.get('ssl.cert_reqs')
436
if self.proxied_host is not None:
437
host = self.proxied_host.split(":", 1)[0]
440
if cert_reqs == ssl.CERT_NONE:
441
ui.ui_factory.show_user_warning('not_checking_ssl_cert', host=host)
442
ui.ui_factory.suppressed_warnings.add('not_checking_ssl_cert')
445
if self.ca_certs is None:
446
ca_certs = config_stack.get('ssl.ca_certs')
448
ca_certs = self.ca_certs
451
"No valid trusted SSL CA certificates file set. See "
452
"'bzr help ssl.ca_certs' for more information on setting "
455
ssl_sock = ssl.wrap_socket(
456
self.sock, self.key_file, self.cert_file,
457
cert_reqs=cert_reqs, ca_certs=ca_certs)
461
"See `bzr help ssl.ca_certs` for how to specify trusted CA"
463
"Pass -Ossl.cert_reqs=none to disable certificate "
464
"verification entirely.\n")
466
if cert_reqs == ssl.CERT_REQUIRED:
467
peer_cert = ssl_sock.getpeercert()
468
ssl.match_hostname(peer_cert, host)
349
470
# Wrap the ssl socket before anybody use it
350
471
self._wrap_socket_for_reporting(ssl_sock)
660
783
% (request, request.connection.sock.getsockname())
661
784
response = connection.getresponse()
662
785
convert_to_addinfourl = True
786
except (ssl.SSLError, ssl.CertificateError):
787
# Something is wrong with either the certificate or the hostname,
788
# re-trying won't help
663
790
except (socket.gaierror, httplib.BadStatusLine, httplib.UnknownProtocol,
664
791
socket.error, httplib.HTTPException):
665
792
response = self.retry_or_raise(http_class, request, first_try)