sslutil: document and slightly refactor validation logic
This main purpose of this patch is to make it clearer that fingerprint
pinning takes precedence over CA verification. This will make
subsequent refactoring to the validation code easier to read.
--- a/mercurial/sslutil.py Sun Apr 10 11:00:41 2016 -0700
+++ b/mercurial/sslutil.py Sun Apr 10 11:02:58 2016 -0700
@@ -264,8 +264,6 @@
def __call__(self, sock, strict=False):
host = self.host
- cacerts = self.ui.config('web', 'cacerts')
- hostfingerprints = self.ui.configlist('hostfingerprints', host)
if not sock.cipher(): # work around http://bugs.python.org/issue13721
raise error.Abort(_('%s ssl connection error') % host)
@@ -278,6 +276,10 @@
if not peercert:
raise error.Abort(_('%s certificate error: '
'no certificate received') % host)
+
+ # If a certificate fingerprint is pinned, use it and only it to
+ # validate the remote cert.
+ hostfingerprints = self.ui.configlist('hostfingerprints', host)
peerfingerprint = util.sha1(peercert).hexdigest()
nicefingerprint = ":".join([peerfingerprint[x:x + 2]
for x in xrange(0, len(peerfingerprint), 2)])
@@ -294,7 +296,11 @@
hint=_('check hostfingerprint configuration'))
self.ui.debug('%s certificate matched fingerprint %s\n' %
(host, nicefingerprint))
- elif cacerts != '!':
+ return
+
+ # No pinned fingerprint. Establish trust by looking at the CAs.
+ cacerts = self.ui.config('web', 'cacerts')
+ if cacerts != '!':
msg = _verifycert(peercert2, host)
if msg:
raise error.Abort(_('%s certificate error: %s') % (host, msg),