[PATCH 4 of 6] sslutil: store and use hostname and ui in socket instance

Gregory Szorc gregory.szorc at gmail.com
Sun May 15 14:57:21 EDT 2016


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1463337131 25200
#      Sun May 15 11:32:11 2016 -0700
# Node ID af91b3c6355344f173606b676c7b675e77520898
# Parent  f139b7d229a5d0d99c8d372e81ffaa053b3c3f77
sslutil: store and use hostname and ui in socket instance

Currently, we pass a hostname and ui to sslutil.wrap_socket()
then create a separate sslutil.validator instance also from
a hostname and ui. There is a 1:1 mapping between a wrapped
socket and a validator instance. This commit lays the groundwork
for making the validation function generic by storing the
hostname and ui instance in the state dict attached to the
socket instance and then using these variables in the
validator function.

Since the arguments to sslutil.validator.__init__ are no longer
used, we make them optional and make __init__ a no-op.

diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py
--- a/mercurial/sslutil.py
+++ b/mercurial/sslutil.py
@@ -168,16 +168,18 @@ def wrapsocket(sock, keyfile, certfile, 
     # check if wrap_socket failed silently because socket had been
     # closed
     # - see http://bugs.python.org/issue13721
     if not sslsocket.cipher():
         raise error.Abort(_('ssl connection failed'))
 
     sslsocket._hgstate = {
         'caloaded': caloaded,
+        'hostname': serverhostname,
+        'ui': ui,
     }
 
     return sslsocket
 
 def _verifycert(cert, hostname):
     '''Verify that cert (in socket.getpeercert() format) matches hostname.
     CRLs is not handled.
 
@@ -285,80 +287,80 @@ def sslkwargs(ui, host):
     # FUTURE this can disappear once wrapsocket() is secure by default.
     if _canloaddefaultcerts:
         kws['cert_reqs'] = ssl.CERT_REQUIRED
         return kws
 
     return kws
 
 class validator(object):
-    def __init__(self, ui, host):
-        self.ui = ui
-        self.host = host
+    def __init__(self, ui=None, host=None):
+        pass
 
     def __call__(self, sock, strict=False):
-        host = self.host
+        host = sock._hgstate['hostname']
+        ui = sock._hgstate['ui']
 
         if not sock.cipher(): # work around http://bugs.python.org/issue13721
             raise error.Abort(_('%s ssl connection error') % host)
         try:
             peercert = sock.getpeercert(True)
             peercert2 = sock.getpeercert()
         except AttributeError:
             raise error.Abort(_('%s ssl connection error') % host)
 
         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)
+        hostfingerprints = ui.configlist('hostfingerprints', host)
         peerfingerprint = util.sha1(peercert).hexdigest()
         nicefingerprint = ":".join([peerfingerprint[x:x + 2]
             for x in xrange(0, len(peerfingerprint), 2)])
         if hostfingerprints:
             fingerprintmatch = False
             for hostfingerprint in hostfingerprints:
                 if peerfingerprint.lower() == \
                         hostfingerprint.replace(':', '').lower():
                     fingerprintmatch = True
                     break
             if not fingerprintmatch:
                 raise error.Abort(_('certificate for %s has unexpected '
                                    'fingerprint %s') % (host, nicefingerprint),
                                  hint=_('check hostfingerprint configuration'))
-            self.ui.debug('%s certificate matched fingerprint %s\n' %
-                          (host, nicefingerprint))
+            ui.debug('%s certificate matched fingerprint %s\n' %
+                     (host, nicefingerprint))
             return
 
         # If insecure connections were explicitly requested via --insecure,
         # print a warning and do no verification.
         #
         # It may seem odd that this is checked *after* host fingerprint pinning.
         # This is for backwards compatibility (for now). The message is also
         # the same as below for BC.
-        if self.ui.insecureconnections:
-            self.ui.warn(_('warning: %s certificate with fingerprint %s not '
-                           'verified (check hostfingerprints or web.cacerts '
-                           'config setting)\n') %
-                         (host, nicefingerprint))
+        if ui.insecureconnections:
+            ui.warn(_('warning: %s certificate with fingerprint %s not '
+                      'verified (check hostfingerprints or web.cacerts '
+                      'config setting)\n') %
+                    (host, nicefingerprint))
             return
 
         if not sock._hgstate['caloaded']:
             if strict:
                 raise error.Abort(_('%s certificate with fingerprint %s not '
                                     'verified') % (host, nicefingerprint),
                                   hint=_('check hostfingerprints or '
                                          'web.cacerts config setting'))
             else:
-                self.ui.warn(_('warning: %s certificate with fingerprint %s '
-                               'not verified (check hostfingerprints or '
-                               'web.cacerts config setting)\n') %
-                             (host, nicefingerprint))
+                ui.warn(_('warning: %s certificate with fingerprint %s '
+                          'not verified (check hostfingerprints or '
+                          'web.cacerts config setting)\n') %
+                        (host, nicefingerprint))
 
             return
 
         msg = _verifycert(peercert2, host)
         if msg:
             raise error.Abort(_('%s certificate error: %s') % (host, msg),
                              hint=_('configure hostfingerprint %s or use '
                                     '--insecure to connect insecurely') %


More information about the Mercurial-devel mailing list