Patchwork [3,of,5,V2] sslutil: store and use hostname and ui in socket instance

login
register
mail settings
Submitter Gregory Szorc
Date May 15, 2016, 11:18 p.m.
Message ID <7b8fd0e68768a980b114.1463354320@ubuntu-vm-main>
Download mbox | patch
Permalink /patch/15126/
State Accepted
Headers show

Comments

Gregory Szorc - May 15, 2016, 11:18 p.m.
# HG changeset patch
# User Gregory Szorc <gregory.szorc@gmail.com>
# Date 1463337131 25200
#      Sun May 15 11:32:11 2016 -0700
# Node ID 7b8fd0e68768a980b114176cf809c6f1b283133d
# Parent  0a4ddbaae306c1e8a28abc37c54fe29f94042996
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.

Patch

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') %