mercurial/sslutil.py
changeset 44875 7c19eb372438
parent 44873 47b3c8383cc1
child 44876 dca2629f6d2e
equal deleted inserted replaced
44874:4c53c12b92d5 44875:7c19eb372438
    31 
    31 
    32 # Python 2.7.9+ overhauled the built-in SSL/TLS features of Python. It added
    32 # Python 2.7.9+ overhauled the built-in SSL/TLS features of Python. It added
    33 # support for TLS 1.1, TLS 1.2, SNI, system CA stores, etc. These features are
    33 # support for TLS 1.1, TLS 1.2, SNI, system CA stores, etc. These features are
    34 # all exposed via the "ssl" module.
    34 # all exposed via the "ssl" module.
    35 #
    35 #
    36 # Depending on the version of Python being used, SSL/TLS support is either
    36 # We require in setup.py the presence of ssl.SSLContext, which indicates modern
    37 # modern/secure or legacy/insecure. Many operations in this module have
    37 # SSL/TLS support.
    38 # separate code paths depending on support in Python.
       
    39 
    38 
    40 configprotocols = {
    39 configprotocols = {
    41     b'tls1.0',
    40     b'tls1.0',
    42     b'tls1.1',
    41     b'tls1.1',
    43     b'tls1.2',
    42     b'tls1.2',
    51 if util.safehasattr(ssl, b'PROTOCOL_TLSv1_1'):
    50 if util.safehasattr(ssl, b'PROTOCOL_TLSv1_1'):
    52     supportedprotocols.add(b'tls1.1')
    51     supportedprotocols.add(b'tls1.1')
    53 if util.safehasattr(ssl, b'PROTOCOL_TLSv1_2'):
    52 if util.safehasattr(ssl, b'PROTOCOL_TLSv1_2'):
    54     supportedprotocols.add(b'tls1.2')
    53     supportedprotocols.add(b'tls1.2')
    55 
    54 
    56 try:
    55 modernssl = True
    57     # ssl.SSLContext was added in 2.7.9 and presence indicates modern
    56 _canloaddefaultcerts = True
    58     # SSL/TLS features are available.
       
    59     SSLContext = ssl.SSLContext
       
    60     modernssl = True
       
    61     _canloaddefaultcerts = True
       
    62 except AttributeError:
       
    63     modernssl = False
       
    64     _canloaddefaultcerts = False
       
    65 
       
    66     # We implement SSLContext using the interface from the standard library.
       
    67     class SSLContext(object):
       
    68         def __init__(self, protocol):
       
    69             # From the public interface of SSLContext
       
    70             self.protocol = protocol
       
    71             self.check_hostname = False
       
    72             self.options = 0
       
    73             self.verify_mode = ssl.CERT_NONE
       
    74 
       
    75             # Used by our implementation.
       
    76             self._certfile = None
       
    77             self._keyfile = None
       
    78             self._certpassword = None
       
    79             self._cacerts = None
       
    80             self._ciphers = None
       
    81 
       
    82         def load_cert_chain(self, certfile, keyfile=None, password=None):
       
    83             self._certfile = certfile
       
    84             self._keyfile = keyfile
       
    85             self._certpassword = password
       
    86 
       
    87         def load_default_certs(self, purpose=None):
       
    88             pass
       
    89 
       
    90         def load_verify_locations(self, cafile=None, capath=None, cadata=None):
       
    91             if capath:
       
    92                 raise error.Abort(_(b'capath not supported'))
       
    93             if cadata:
       
    94                 raise error.Abort(_(b'cadata not supported'))
       
    95 
       
    96             self._cacerts = cafile
       
    97 
       
    98         def set_ciphers(self, ciphers):
       
    99             self._ciphers = ciphers
       
   100 
       
   101         def wrap_socket(self, socket, server_hostname=None, server_side=False):
       
   102             # server_hostname is unique to SSLContext.wrap_socket and is used
       
   103             # for SNI in that context. So there's nothing for us to do with it
       
   104             # in this legacy code since we don't support SNI.
       
   105 
       
   106             args = {
       
   107                 'keyfile': self._keyfile,
       
   108                 'certfile': self._certfile,
       
   109                 'server_side': server_side,
       
   110                 'cert_reqs': self.verify_mode,
       
   111                 'ssl_version': self.protocol,
       
   112                 'ca_certs': self._cacerts,
       
   113                 'ciphers': self._ciphers,
       
   114             }
       
   115 
       
   116             return ssl.wrap_socket(socket, **args)
       
   117 
    57 
   118 
    58 
   119 def _hostsettings(ui, hostname):
    59 def _hostsettings(ui, hostname):
   120     """Obtain security settings for a hostname.
    60     """Obtain security settings for a hostname.
   121 
    61 
   412     # have explicit control over CA loading because implicitly loading
   352     # have explicit control over CA loading because implicitly loading
   413     # CAs may undermine the user's intent. For example, a user may define a CA
   353     # CAs may undermine the user's intent. For example, a user may define a CA
   414     # bundle with a specific CA cert removed. If the system/default CA bundle
   354     # bundle with a specific CA cert removed. If the system/default CA bundle
   415     # is loaded and contains that removed CA, you've just undone the user's
   355     # is loaded and contains that removed CA, you've just undone the user's
   416     # choice.
   356     # choice.
   417     sslcontext = SSLContext(settings[b'protocol'])
   357     sslcontext = ssl.SSLContext(settings[b'protocol'])
   418 
   358 
   419     # This is a no-op unless using modern ssl.
   359     # This is a no-op unless using modern ssl.
   420     sslcontext.options |= settings[b'ctxoptions']
   360     sslcontext.options |= settings[b'ctxoptions']
   421 
   361 
   422     # This still works on our fake SSLContext.
   362     # This still works on our fake SSLContext.
   640 
   580 
   641     if modernssl:
   581     if modernssl:
   642         # We /could/ use create_default_context() here since it doesn't load
   582         # We /could/ use create_default_context() here since it doesn't load
   643         # CAs when configured for client auth. However, it is hard-coded to
   583         # CAs when configured for client auth. However, it is hard-coded to
   644         # use ssl.PROTOCOL_SSLv23 which may not be appropriate here.
   584         # use ssl.PROTOCOL_SSLv23 which may not be appropriate here.
   645         sslcontext = SSLContext(protocol)
   585         sslcontext = ssl.SSLContext(protocol)
   646         sslcontext.options |= options
   586         sslcontext.options |= options
   647 
   587 
   648         # Improve forward secrecy.
   588         # Improve forward secrecy.
   649         sslcontext.options |= getattr(ssl, 'OP_SINGLE_DH_USE', 0)
   589         sslcontext.options |= getattr(ssl, 'OP_SINGLE_DH_USE', 0)
   650         sslcontext.options |= getattr(ssl, 'OP_SINGLE_ECDH_USE', 0)
   590         sslcontext.options |= getattr(ssl, 'OP_SINGLE_ECDH_USE', 0)
   652         # Use the list of more secure ciphers if found in the ssl module.
   592         # Use the list of more secure ciphers if found in the ssl module.
   653         if util.safehasattr(ssl, b'_RESTRICTED_SERVER_CIPHERS'):
   593         if util.safehasattr(ssl, b'_RESTRICTED_SERVER_CIPHERS'):
   654             sslcontext.options |= getattr(ssl, 'OP_CIPHER_SERVER_PREFERENCE', 0)
   594             sslcontext.options |= getattr(ssl, 'OP_CIPHER_SERVER_PREFERENCE', 0)
   655             sslcontext.set_ciphers(ssl._RESTRICTED_SERVER_CIPHERS)
   595             sslcontext.set_ciphers(ssl._RESTRICTED_SERVER_CIPHERS)
   656     else:
   596     else:
   657         sslcontext = SSLContext(ssl.PROTOCOL_TLSv1)
   597         sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
   658 
   598 
   659     if requireclientcert:
   599     if requireclientcert:
   660         sslcontext.verify_mode = ssl.CERT_REQUIRED
   600         sslcontext.verify_mode = ssl.CERT_REQUIRED
   661     else:
   601     else:
   662         sslcontext.verify_mode = ssl.CERT_NONE
   602         sslcontext.verify_mode = ssl.CERT_NONE