comparison mercurial/url.py @ 13314:8dc488dfcdb4 stable

url: 'ssh known host'-like checking of fingerprints of HTTPS certificates Known fingerprints of HTTPS servers can now be configured in the hostfingerprints section. That makes it possible to verify the identify of web servers without configuring and trusting the CA chain. Limitations: * Portnumbers are ignored, just like with ordinary certificates. * Host name matching is case sensitive.
author Mads Kiilerich <mads@kiilerich.com>
date Fri, 28 Jan 2011 02:57:59 +0100
parents 75d0c38a0bca
children 0d1dca7d2a04 a939f08fae9c
comparison
equal deleted inserted replaced
13312:9f188734dbb0 13314:8dc488dfcdb4
531 if cacerts: 531 if cacerts:
532 cacerts = util.expandpath(cacerts) 532 cacerts = util.expandpath(cacerts)
533 else: 533 else:
534 cacerts = None 534 cacerts = None
535 535
536 if cacerts: 536 hostfingerprint = self.ui.config('hostfingerprints', self.host)
537 if cacerts and not hostfingerprint:
537 sock = _create_connection((self.host, self.port)) 538 sock = _create_connection((self.host, self.port))
538 self.sock = _ssl_wrap_socket(sock, self.key_file, 539 self.sock = _ssl_wrap_socket(sock, self.key_file,
539 self.cert_file, cert_reqs=CERT_REQUIRED, 540 self.cert_file, cert_reqs=CERT_REQUIRED,
540 ca_certs=cacerts) 541 ca_certs=cacerts)
541 msg = _verifycert(self.sock.getpeercert(), self.host) 542 msg = _verifycert(self.sock.getpeercert(), self.host)
543 raise util.Abort(_('%s certificate error: %s') % 544 raise util.Abort(_('%s certificate error: %s') %
544 (self.host, msg)) 545 (self.host, msg))
545 self.ui.debug('%s certificate successfully verified\n' % 546 self.ui.debug('%s certificate successfully verified\n' %
546 self.host) 547 self.host)
547 else: 548 else:
548 self.ui.warn(_("warning: %s certificate not verified "
549 "(check web.cacerts config setting)\n") %
550 self.host)
551 httplib.HTTPSConnection.connect(self) 549 httplib.HTTPSConnection.connect(self)
550 if hasattr(self.sock, 'getpeercert'):
551 peercert = self.sock.getpeercert(True)
552 peerfingerprint = util.sha1(peercert).hexdigest()
553 nicefingerprint = ":".join([peerfingerprint[x:x + 2]
554 for x in xrange(0, len(peerfingerprint), 2)])
555 if hostfingerprint:
556 if peerfingerprint.lower() != \
557 hostfingerprint.replace(':', '').lower():
558 raise util.Abort(_('invalid certificate for %s '
559 'with fingerprint %s') %
560 (self.host, nicefingerprint))
561 self.ui.debug('%s certificate matched fingerprint %s\n' %
562 (self.host, nicefingerprint))
563 else:
564 self.ui.warn(_('warning: %s certificate '
565 'with fingerprint %s not verified '
566 '(check hostfingerprints or web.cacerts '
567 'config setting)\n') %
568 (self.host, nicefingerprint))
569 else: # python 2.5 ?
570 if hostfingerprint:
571 raise util.Abort(_('no certificate for %s '
572 'with fingerprint') % self.host)
573 self.ui.warn(_('warning: %s certificate not verified '
574 '(check web.cacerts config setting)\n') %
575 self.host)
552 576
553 class httpsconnection(BetterHTTPS): 577 class httpsconnection(BetterHTTPS):
554 response_class = keepalive.HTTPResponse 578 response_class = keepalive.HTTPResponse
555 # must be able to send big bundle as stream. 579 # must be able to send big bundle as stream.
556 send = _gen_sendfile(BetterHTTPS) 580 send = _gen_sendfile(BetterHTTPS)