# HG changeset patch # User Wagner Bruna # Date 1296255717 7200 # Node ID ed2a83a51a65466922d26a621986c7502f4ecf78 # Parent 8dc488dfcdb4e23d929d12cfab4037c77d2e227f# Parent 11cc2b86386678679885f5572eff693d2aceded2 merge with i18n stable diff -r 11cc2b863866 -r ed2a83a51a65 doc/hgrc.5.txt --- a/doc/hgrc.5.txt Fri Jan 28 13:31:17 2011 -0200 +++ b/doc/hgrc.5.txt Fri Jan 28 21:01:57 2011 -0200 @@ -423,6 +423,24 @@ myfeature = ~/.hgext/myfeature.py +``hostfingerprints`` +"""""""""""""""""""" + +Fingerprints of the certificates of known HTTPS servers. +A HTTPS connection to a server with a fingerprint configured here will +only succeed if the servers certificate matches the fingerprint. +This is very similar to how ssh known hosts works. +The fingerprint is the SHA-1 hash value of the DER encoded certificate. +The CA chain and web.cacerts is not used for servers with a fingerprint. + +For example:: + + [hostfingerprints] + hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc + +This feature is only supported when using Python 2.6 or later. + + ``format`` """""""""" diff -r 11cc2b863866 -r ed2a83a51a65 mercurial/hg.py --- a/mercurial/hg.py Fri Jan 28 13:31:17 2011 -0200 +++ b/mercurial/hg.py Fri Jan 28 21:01:57 2011 -0200 @@ -546,7 +546,7 @@ dst.setconfig('bundle', 'mainreporoot', r) # copy selected local settings to the remote ui - for sect in ('auth', 'http_proxy'): + for sect in ('auth', 'hostfingerprints', 'http_proxy'): for key, val in src.configitems(sect): dst.setconfig(sect, key, val) v = src.config('web', 'cacerts') diff -r 11cc2b863866 -r ed2a83a51a65 mercurial/url.py --- a/mercurial/url.py Fri Jan 28 13:31:17 2011 -0200 +++ b/mercurial/url.py Fri Jan 28 21:01:57 2011 -0200 @@ -533,7 +533,8 @@ else: cacerts = None - if cacerts: + hostfingerprint = self.ui.config('hostfingerprints', self.host) + if cacerts and not hostfingerprint: sock = _create_connection((self.host, self.port)) self.sock = _ssl_wrap_socket(sock, self.key_file, self.cert_file, cert_reqs=CERT_REQUIRED, @@ -545,10 +546,33 @@ self.ui.debug('%s certificate successfully verified\n' % self.host) else: - self.ui.warn(_("warning: %s certificate not verified " - "(check web.cacerts config setting)\n") % - self.host) httplib.HTTPSConnection.connect(self) + if hasattr(self.sock, 'getpeercert'): + peercert = self.sock.getpeercert(True) + peerfingerprint = util.sha1(peercert).hexdigest() + nicefingerprint = ":".join([peerfingerprint[x:x + 2] + for x in xrange(0, len(peerfingerprint), 2)]) + if hostfingerprint: + if peerfingerprint.lower() != \ + hostfingerprint.replace(':', '').lower(): + raise util.Abort(_('invalid certificate for %s ' + 'with fingerprint %s') % + (self.host, nicefingerprint)) + self.ui.debug('%s certificate matched fingerprint %s\n' % + (self.host, nicefingerprint)) + else: + self.ui.warn(_('warning: %s certificate ' + 'with fingerprint %s not verified ' + '(check hostfingerprints or web.cacerts ' + 'config setting)\n') % + (self.host, nicefingerprint)) + else: # python 2.5 ? + if hostfingerprint: + raise util.Abort(_('no certificate for %s ' + 'with fingerprint') % self.host) + self.ui.warn(_('warning: %s certificate not verified ' + '(check web.cacerts config setting)\n') % + self.host) class httpsconnection(BetterHTTPS): response_class = keepalive.HTTPResponse diff -r 11cc2b863866 -r ed2a83a51a65 tests/test-https.t --- a/tests/test-https.t Fri Jan 28 13:31:17 2011 -0200 +++ b/tests/test-https.t Fri Jan 28 21:01:57 2011 -0200 @@ -106,7 +106,7 @@ clone via pull $ hg clone https://localhost:$HGPORT/ copy-pull - warning: localhost certificate not verified (check web.cacerts config setting) + warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting) requesting all changes adding changesets adding manifests @@ -132,7 +132,7 @@ $ echo '[hooks]' >> .hg/hgrc $ echo "changegroup = python '$TESTDIR'/printenv.py changegroup" >> .hg/hgrc $ hg pull - warning: localhost certificate not verified (check web.cacerts config setting) + warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting) changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/ pulling from https://localhost:$HGPORT/ searching for changes @@ -188,3 +188,22 @@ $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/ abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob) [255] + +Fingerprints + + $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc + $ echo "localhost = 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca" >> copy-pull/.hg/hgrc + $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc + +- works without cacerts + $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts= + 5fed3813f7f5 + +- fails when cert doesn't match hostname (port is ignored) + $ hg -R copy-pull id https://localhost:$HGPORT1/ + abort: invalid certificate for localhost with fingerprint 28:ff:71:bf:65:31:14:23:ad:62:92:b4:0e:31:99:18:fc:83:e3:9b + [255] + +- ignores that certificate doesn't match hostname + $ hg -R copy-pull id https://127.0.0.1:$HGPORT/ + 5fed3813f7f5