mercurial/sslutil.py
changeset 29226 33006bd6a1d7
parent 29225 b115eed11780
child 29227 dffe78d80a6c
equal deleted inserted replaced
29225:b115eed11780 29226:33006bd6a1d7
   171     if not sslsocket.cipher():
   171     if not sslsocket.cipher():
   172         raise error.Abort(_('ssl connection failed'))
   172         raise error.Abort(_('ssl connection failed'))
   173 
   173 
   174     sslsocket._hgstate = {
   174     sslsocket._hgstate = {
   175         'caloaded': caloaded,
   175         'caloaded': caloaded,
       
   176         'hostname': serverhostname,
       
   177         'ui': ui,
   176     }
   178     }
   177 
   179 
   178     return sslsocket
   180     return sslsocket
   179 
   181 
   180 def _verifycert(cert, hostname):
   182 def _verifycert(cert, hostname):
   288         return kws
   290         return kws
   289 
   291 
   290     return kws
   292     return kws
   291 
   293 
   292 class validator(object):
   294 class validator(object):
   293     def __init__(self, ui, host):
   295     def __init__(self, ui=None, host=None):
   294         self.ui = ui
   296         pass
   295         self.host = host
       
   296 
   297 
   297     def __call__(self, sock, strict=False):
   298     def __call__(self, sock, strict=False):
   298         host = self.host
   299         host = sock._hgstate['hostname']
       
   300         ui = sock._hgstate['ui']
   299 
   301 
   300         if not sock.cipher(): # work around http://bugs.python.org/issue13721
   302         if not sock.cipher(): # work around http://bugs.python.org/issue13721
   301             raise error.Abort(_('%s ssl connection error') % host)
   303             raise error.Abort(_('%s ssl connection error') % host)
   302         try:
   304         try:
   303             peercert = sock.getpeercert(True)
   305             peercert = sock.getpeercert(True)
   309             raise error.Abort(_('%s certificate error: '
   311             raise error.Abort(_('%s certificate error: '
   310                                'no certificate received') % host)
   312                                'no certificate received') % host)
   311 
   313 
   312         # If a certificate fingerprint is pinned, use it and only it to
   314         # If a certificate fingerprint is pinned, use it and only it to
   313         # validate the remote cert.
   315         # validate the remote cert.
   314         hostfingerprints = self.ui.configlist('hostfingerprints', host)
   316         hostfingerprints = ui.configlist('hostfingerprints', host)
   315         peerfingerprint = util.sha1(peercert).hexdigest()
   317         peerfingerprint = util.sha1(peercert).hexdigest()
   316         nicefingerprint = ":".join([peerfingerprint[x:x + 2]
   318         nicefingerprint = ":".join([peerfingerprint[x:x + 2]
   317             for x in xrange(0, len(peerfingerprint), 2)])
   319             for x in xrange(0, len(peerfingerprint), 2)])
   318         if hostfingerprints:
   320         if hostfingerprints:
   319             fingerprintmatch = False
   321             fingerprintmatch = False
   324                     break
   326                     break
   325             if not fingerprintmatch:
   327             if not fingerprintmatch:
   326                 raise error.Abort(_('certificate for %s has unexpected '
   328                 raise error.Abort(_('certificate for %s has unexpected '
   327                                    'fingerprint %s') % (host, nicefingerprint),
   329                                    'fingerprint %s') % (host, nicefingerprint),
   328                                  hint=_('check hostfingerprint configuration'))
   330                                  hint=_('check hostfingerprint configuration'))
   329             self.ui.debug('%s certificate matched fingerprint %s\n' %
   331             ui.debug('%s certificate matched fingerprint %s\n' %
   330                           (host, nicefingerprint))
   332                      (host, nicefingerprint))
   331             return
   333             return
   332 
   334 
   333         # If insecure connections were explicitly requested via --insecure,
   335         # If insecure connections were explicitly requested via --insecure,
   334         # print a warning and do no verification.
   336         # print a warning and do no verification.
   335         #
   337         #
   336         # It may seem odd that this is checked *after* host fingerprint pinning.
   338         # It may seem odd that this is checked *after* host fingerprint pinning.
   337         # This is for backwards compatibility (for now). The message is also
   339         # This is for backwards compatibility (for now). The message is also
   338         # the same as below for BC.
   340         # the same as below for BC.
   339         if self.ui.insecureconnections:
   341         if ui.insecureconnections:
   340             self.ui.warn(_('warning: %s certificate with fingerprint %s not '
   342             ui.warn(_('warning: %s certificate with fingerprint %s not '
   341                            'verified (check hostfingerprints or web.cacerts '
   343                       'verified (check hostfingerprints or web.cacerts '
   342                            'config setting)\n') %
   344                       'config setting)\n') %
   343                          (host, nicefingerprint))
   345                     (host, nicefingerprint))
   344             return
   346             return
   345 
   347 
   346         if not sock._hgstate['caloaded']:
   348         if not sock._hgstate['caloaded']:
   347             if strict:
   349             if strict:
   348                 raise error.Abort(_('%s certificate with fingerprint %s not '
   350                 raise error.Abort(_('%s certificate with fingerprint %s not '
   349                                     'verified') % (host, nicefingerprint),
   351                                     'verified') % (host, nicefingerprint),
   350                                   hint=_('check hostfingerprints or '
   352                                   hint=_('check hostfingerprints or '
   351                                          'web.cacerts config setting'))
   353                                          'web.cacerts config setting'))
   352             else:
   354             else:
   353                 self.ui.warn(_('warning: %s certificate with fingerprint %s '
   355                 ui.warn(_('warning: %s certificate with fingerprint %s '
   354                                'not verified (check hostfingerprints or '
   356                           'not verified (check hostfingerprints or '
   355                                'web.cacerts config setting)\n') %
   357                           'web.cacerts config setting)\n') %
   356                              (host, nicefingerprint))
   358                         (host, nicefingerprint))
   357 
   359 
   358             return
   360             return
   359 
   361 
   360         msg = _verifycert(peercert2, host)
   362         msg = _verifycert(peercert2, host)
   361         if msg:
   363         if msg: