comparison mercurial/sslutil.py @ 44875:7c19eb372438

sslutil: remove code checking for presence of ssl.SSLContext Now that we require the presence of ssl.SSLContext in setup.py, we can remove this code.
author Manuel Jacob <me@manueljacob.de>
date Fri, 29 May 2020 21:18:22 +0200
parents 47b3c8383cc1
children dca2629f6d2e
comparison
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