mercurial/sslutil.py
branchstable
changeset 29618 fbf4adc0d8f2
parent 29617 2960ceee1948
child 29619 53e80179bd6a
equal deleted inserted replaced
29617:2960ceee1948 29618:fbf4adc0d8f2
   137         'disablecertverification': False,
   137         'disablecertverification': False,
   138         # Whether the legacy [hostfingerprints] section has data for this host.
   138         # Whether the legacy [hostfingerprints] section has data for this host.
   139         'legacyfingerprint': False,
   139         'legacyfingerprint': False,
   140         # PROTOCOL_* constant to use for SSLContext.__init__.
   140         # PROTOCOL_* constant to use for SSLContext.__init__.
   141         'protocol': None,
   141         'protocol': None,
       
   142         # String representation of minimum protocol to be used for UI
       
   143         # presentation.
       
   144         'protocolui': None,
   142         # ssl.CERT_* constant used by SSLContext.verify_mode.
   145         # ssl.CERT_* constant used by SSLContext.verify_mode.
   143         'verifymode': None,
   146         'verifymode': None,
   144         # Defines extra ssl.OP* bitwise options to set.
   147         # Defines extra ssl.OP* bitwise options to set.
   145         'ctxoptions': None,
   148         'ctxoptions': None,
   146         # OpenSSL Cipher List to use (instead of default).
   149         # OpenSSL Cipher List to use (instead of default).
   185     # We always print a "connection security to %s is disabled..." message when
   188     # We always print a "connection security to %s is disabled..." message when
   186     # --insecure is used. So no need to print anything more here.
   189     # --insecure is used. So no need to print anything more here.
   187     if ui.insecureconnections:
   190     if ui.insecureconnections:
   188         protocol = 'tls1.0'
   191         protocol = 'tls1.0'
   189 
   192 
   190     s['protocol'], s['ctxoptions'] = protocolsettings(protocol)
   193     s['protocol'], s['ctxoptions'], s['protocolui'] = protocolsettings(protocol)
   191 
   194 
   192     ciphers = ui.config('hostsecurity', 'ciphers')
   195     ciphers = ui.config('hostsecurity', 'ciphers')
   193     ciphers = ui.config('hostsecurity', '%s:ciphers' % hostname, ciphers)
   196     ciphers = ui.config('hostsecurity', '%s:ciphers' % hostname, ciphers)
   194     s['ciphers'] = ciphers
   197     s['ciphers'] = ciphers
   195 
   198 
   283     assert s['verifymode'] is not None
   286     assert s['verifymode'] is not None
   284 
   287 
   285     return s
   288     return s
   286 
   289 
   287 def protocolsettings(protocol):
   290 def protocolsettings(protocol):
   288     """Resolve the protocol and context options for a config value."""
   291     """Resolve the protocol for a config value.
       
   292 
       
   293     Returns a 3-tuple of (protocol, options, ui value) where the first
       
   294     2 items are values used by SSLContext and the last is a string value
       
   295     of the ``minimumprotocol`` config option equivalent.
       
   296     """
   289     if protocol not in configprotocols:
   297     if protocol not in configprotocols:
   290         raise ValueError('protocol value not supported: %s' % protocol)
   298         raise ValueError('protocol value not supported: %s' % protocol)
   291 
   299 
   292     # Despite its name, PROTOCOL_SSLv23 selects the highest protocol
   300     # Despite its name, PROTOCOL_SSLv23 selects the highest protocol
   293     # that both ends support, including TLS protocols. On legacy stacks,
   301     # that both ends support, including TLS protocols. On legacy stacks,
   305             raise error.Abort(_('current Python does not support protocol '
   313             raise error.Abort(_('current Python does not support protocol '
   306                                 'setting %s') % protocol,
   314                                 'setting %s') % protocol,
   307                               hint=_('upgrade Python or disable setting since '
   315                               hint=_('upgrade Python or disable setting since '
   308                                      'only TLS 1.0 is supported'))
   316                                      'only TLS 1.0 is supported'))
   309 
   317 
   310         return ssl.PROTOCOL_TLSv1, 0
   318         return ssl.PROTOCOL_TLSv1, 0, 'tls1.0'
   311 
   319 
   312     # WARNING: returned options don't work unless the modern ssl module
   320     # WARNING: returned options don't work unless the modern ssl module
   313     # is available. Be careful when adding options here.
   321     # is available. Be careful when adding options here.
   314 
   322 
   315     # SSLv2 and SSLv3 are broken. We ban them outright.
   323     # SSLv2 and SSLv3 are broken. We ban them outright.
   327 
   335 
   328     # Prevent CRIME.
   336     # Prevent CRIME.
   329     # There is no guarantee this attribute is defined on the module.
   337     # There is no guarantee this attribute is defined on the module.
   330     options |= getattr(ssl, 'OP_NO_COMPRESSION', 0)
   338     options |= getattr(ssl, 'OP_NO_COMPRESSION', 0)
   331 
   339 
   332     return ssl.PROTOCOL_SSLv23, options
   340     return ssl.PROTOCOL_SSLv23, options, protocol
   333 
   341 
   334 def wrapsocket(sock, keyfile, certfile, ui, serverhostname=None):
   342 def wrapsocket(sock, keyfile, certfile, ui, serverhostname=None):
   335     """Add SSL/TLS to a socket.
   343     """Add SSL/TLS to a socket.
   336 
   344 
   337     This is a glorified wrapper for ``ssl.wrap_socket()``. It makes sane
   345     This is a glorified wrapper for ``ssl.wrap_socket()``. It makes sane
   443 
   451 
   444     ``requireclientcert`` specifies whether to require client certificates.
   452     ``requireclientcert`` specifies whether to require client certificates.
   445 
   453 
   446     Typically ``cafile`` is only defined if ``requireclientcert`` is true.
   454     Typically ``cafile`` is only defined if ``requireclientcert`` is true.
   447     """
   455     """
   448     protocol, options = protocolsettings('tls1.0')
   456     protocol, options, _protocolui = protocolsettings('tls1.0')
   449 
   457 
   450     # This config option is intended for use in tests only. It is a giant
   458     # This config option is intended for use in tests only. It is a giant
   451     # footgun to kill security. Don't define it.
   459     # footgun to kill security. Don't define it.
   452     exactprotocol = ui.config('devel', 'serverexactprotocol')
   460     exactprotocol = ui.config('devel', 'serverexactprotocol')
   453     if exactprotocol == 'tls1.0':
   461     if exactprotocol == 'tls1.0':