mercurial/sslutil.py
changeset 29268 f200b58497f1
parent 29267 f0ccb6cde3e5
child 29286 a05a91a3f120
equal deleted inserted replaced
29267:f0ccb6cde3e5 29268:f200b58497f1
   115         # List of 2-tuple of (hash algorithm, hash).
   115         # List of 2-tuple of (hash algorithm, hash).
   116         'certfingerprints': [],
   116         'certfingerprints': [],
   117         # Path to file containing concatenated CA certs. Used by
   117         # Path to file containing concatenated CA certs. Used by
   118         # SSLContext.load_verify_locations().
   118         # SSLContext.load_verify_locations().
   119         'cafile': None,
   119         'cafile': None,
       
   120         # Whether the legacy [hostfingerprints] section has data for this host.
       
   121         'legacyfingerprint': False,
   120         # ssl.CERT_* constant used by SSLContext.verify_mode.
   122         # ssl.CERT_* constant used by SSLContext.verify_mode.
   121         'verifymode': None,
   123         'verifymode': None,
   122     }
   124     }
   123 
   125 
   124     # Look for fingerprints in [hostsecurity] section. Value is a list
   126     # Look for fingerprints in [hostsecurity] section. Value is a list
   138 
   140 
   139     # Fingerprints from [hostfingerprints] are always SHA-1.
   141     # Fingerprints from [hostfingerprints] are always SHA-1.
   140     for fingerprint in ui.configlist('hostfingerprints', hostname, []):
   142     for fingerprint in ui.configlist('hostfingerprints', hostname, []):
   141         fingerprint = fingerprint.replace(':', '').lower()
   143         fingerprint = fingerprint.replace(':', '').lower()
   142         s['certfingerprints'].append(('sha1', fingerprint))
   144         s['certfingerprints'].append(('sha1', fingerprint))
       
   145         s['legacyfingerprint'] = True
   143 
   146 
   144     # If a host cert fingerprint is defined, it is the only thing that
   147     # If a host cert fingerprint is defined, it is the only thing that
   145     # matters. No need to validate CA certs.
   148     # matters. No need to validate CA certs.
   146     if s['certfingerprints']:
   149     if s['certfingerprints']:
   147         s['verifymode'] = ssl.CERT_NONE
   150         s['verifymode'] = ssl.CERT_NONE
   348         'sha512': util.sha512(peercert).hexdigest(),
   351         'sha512': util.sha512(peercert).hexdigest(),
   349     }
   352     }
   350     nicefingerprint = ':'.join([peerfingerprints['sha1'][x:x + 2]
   353     nicefingerprint = ':'.join([peerfingerprints['sha1'][x:x + 2]
   351         for x in range(0, len(peerfingerprints['sha1']), 2)])
   354         for x in range(0, len(peerfingerprints['sha1']), 2)])
   352 
   355 
       
   356     if settings['legacyfingerprint']:
       
   357         section = 'hostfingerprint'
       
   358     else:
       
   359         section = 'hostsecurity'
       
   360 
   353     if settings['certfingerprints']:
   361     if settings['certfingerprints']:
   354         fingerprintmatch = False
   362         fingerprintmatch = False
   355         for hash, fingerprint in settings['certfingerprints']:
   363         for hash, fingerprint in settings['certfingerprints']:
   356             if peerfingerprints[hash].lower() == fingerprint:
   364             if peerfingerprints[hash].lower() == fingerprint:
   357                 fingerprintmatch = True
   365                 fingerprintmatch = True
   358                 break
   366                 break
   359         if not fingerprintmatch:
   367         if not fingerprintmatch:
   360             raise error.Abort(_('certificate for %s has unexpected '
   368             raise error.Abort(_('certificate for %s has unexpected '
   361                                'fingerprint %s') % (host, nicefingerprint),
   369                                'fingerprint %s') % (host, nicefingerprint),
   362                              hint=_('check hostfingerprint configuration'))
   370                              hint=_('check %s configuration') % section)
   363         ui.debug('%s certificate matched fingerprint %s\n' %
   371         ui.debug('%s certificate matched fingerprint %s\n' %
   364                  (host, nicefingerprint))
   372                  (host, nicefingerprint))
   365         return
   373         return
   366 
   374 
   367     # If insecure connections were explicitly requested via --insecure,
   375     # If insecure connections were explicitly requested via --insecure,
   370     # It may seem odd that this is checked *after* host fingerprint pinning.
   378     # It may seem odd that this is checked *after* host fingerprint pinning.
   371     # This is for backwards compatibility (for now). The message is also
   379     # This is for backwards compatibility (for now). The message is also
   372     # the same as below for BC.
   380     # the same as below for BC.
   373     if ui.insecureconnections:
   381     if ui.insecureconnections:
   374         ui.warn(_('warning: %s certificate with fingerprint %s not '
   382         ui.warn(_('warning: %s certificate with fingerprint %s not '
   375                   'verified (check hostfingerprints or web.cacerts '
   383                   'verified (check %s or web.cacerts '
   376                   'config setting)\n') %
   384                   'config setting)\n') %
   377                 (host, nicefingerprint))
   385                 (host, nicefingerprint, section))
   378         return
   386         return
   379 
   387 
   380     if not sock._hgstate['caloaded']:
   388     if not sock._hgstate['caloaded']:
   381         if strict:
   389         if strict:
   382             raise error.Abort(_('%s certificate with fingerprint %s not '
   390             raise error.Abort(_('%s certificate with fingerprint %s not '
   383                                 'verified') % (host, nicefingerprint),
   391                                 'verified') % (host, nicefingerprint),
   384                               hint=_('check hostfingerprints or '
   392                               hint=_('check %s or web.cacerts config '
   385                                      'web.cacerts config setting'))
   393                                      'setting') % section)
   386         else:
   394         else:
   387             ui.warn(_('warning: %s certificate with fingerprint %s '
   395             ui.warn(_('warning: %s certificate with fingerprint %s '
   388                       'not verified (check hostfingerprints or '
   396                       'not verified (check %s or web.cacerts config '
   389                       'web.cacerts config setting)\n') %
   397                       'setting)\n') %
   390                     (host, nicefingerprint))
   398                     (host, nicefingerprint, section))
   391 
   399 
   392         return
   400         return
   393 
   401 
   394     msg = _verifycert(peercert2, host)
   402     msg = _verifycert(peercert2, host)
   395     if msg:
   403     if msg:
   396         raise error.Abort(_('%s certificate error: %s') % (host, msg),
   404         raise error.Abort(_('%s certificate error: %s') % (host, msg),
   397                          hint=_('configure hostfingerprint %s or use '
   405                          hint=_('configure %s %s or use '
   398                                 '--insecure to connect insecurely') %
   406                                 '--insecure to connect insecurely') %
   399                               nicefingerprint)
   407                               (section, nicefingerprint))