comparison mercurial/url.py @ 10409:4c94a3df4b10

url: SSL server certificate verification using web.cacerts file (issue1174)
author Henrik Stuart <hg@hstuart.dk>
date Wed, 10 Feb 2010 20:27:46 +0100
parents 50fb1fe143ff
children af4c42ec19ed
comparison
equal deleted inserted replaced
10408:50fb1fe143ff 10409:4c94a3df4b10
253 if has_https: 253 if has_https:
254 try: 254 try:
255 # avoid using deprecated/broken FakeSocket in python 2.6 255 # avoid using deprecated/broken FakeSocket in python 2.6
256 import ssl 256 import ssl
257 _ssl_wrap_socket = ssl.wrap_socket 257 _ssl_wrap_socket = ssl.wrap_socket
258 CERT_REQUIRED = ssl.CERT_REQUIRED
258 except ImportError: 259 except ImportError:
259 def _ssl_wrap_socket(sock, key_file, cert_file): 260 CERT_REQUIRED = 2
261
262 def _ssl_wrap_socket(sock, key_file, cert_file,
263 cert_reqs=CERT_REQUIRED, ca_certs=None):
264 if ca_certs:
265 raise util.Abort(_(
266 'certificate checking requires Python 2.6'))
267
260 ssl = socket.ssl(sock, key_file, cert_file) 268 ssl = socket.ssl(sock, key_file, cert_file)
261 return httplib.FakeSocket(sock, ssl) 269 return httplib.FakeSocket(sock, ssl)
270
271 _GLOBAL_DEFAULT_TIMEOUT = object()
272
273 try:
274 _create_connection = socket.create_connection
275 except ImportError:
276 def _create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
277 source_address=None):
278 # lifted from Python 2.6
279
280 msg = "getaddrinfo returns an empty list"
281 host, port = address
282 for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
283 af, socktype, proto, canonname, sa = res
284 sock = None
285 try:
286 sock = socket.socket(af, socktype, proto)
287 if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
288 sock.settimeout(timeout)
289 if source_address:
290 sock.bind(source_address)
291 sock.connect(sa)
292 return sock
293
294 except socket.error, msg:
295 if sock is not None:
296 sock.close()
297
298 raise socket.error, msg
262 299
263 class httpconnection(keepalive.HTTPConnection): 300 class httpconnection(keepalive.HTTPConnection):
264 # must be able to send big bundle as stream. 301 # must be able to send big bundle as stream.
265 send = _gen_sendfile(keepalive.HTTPConnection) 302 send = _gen_sendfile(keepalive.HTTPConnection)
266 303
425 462
426 if has_https: 463 if has_https:
427 class BetterHTTPS(httplib.HTTPSConnection): 464 class BetterHTTPS(httplib.HTTPSConnection):
428 send = keepalive.safesend 465 send = keepalive.safesend
429 466
467 def connect(self):
468 if hasattr(self, 'ui'):
469 cacerts = self.ui.config('web', 'cacerts')
470 else:
471 cacerts = None
472
473 if cacerts:
474 sock = _create_connection((self.host, self.port))
475 self.sock = _ssl_wrap_socket(sock, self.key_file,
476 self.cert_file, cert_reqs=CERT_REQUIRED,
477 ca_certs=cacerts)
478 self.ui.debug(_('server identity verification succeeded\n'))
479 else:
480 httplib.HTTPSConnection.connect(self)
481
430 class httpsconnection(BetterHTTPS): 482 class httpsconnection(BetterHTTPS):
431 response_class = keepalive.HTTPResponse 483 response_class = keepalive.HTTPResponse
432 # must be able to send big bundle as stream. 484 # must be able to send big bundle as stream.
433 send = _gen_sendfile(BetterHTTPS) 485 send = _gen_sendfile(BetterHTTPS)
434 getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection) 486 getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection)
471 # hgrc, we prefer these 523 # hgrc, we prefer these
472 if self.auth and 'key' in self.auth and 'cert' in self.auth: 524 if self.auth and 'key' in self.auth and 'cert' in self.auth:
473 keyfile = self.auth['key'] 525 keyfile = self.auth['key']
474 certfile = self.auth['cert'] 526 certfile = self.auth['cert']
475 527
476 return httpsconnection(host, port, keyfile, certfile, *args, **kwargs) 528 conn = httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
529 conn.ui = self.ui
530 return conn
477 531
478 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if 532 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
479 # it doesn't know about the auth type requested. This can happen if 533 # it doesn't know about the auth type requested. This can happen if
480 # somebody is using BasicAuth and types a bad password. 534 # somebody is using BasicAuth and types a bad password.
481 class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler): 535 class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler):