10 |
10 |
11 from mercurial import util |
11 from mercurial import util |
12 from mercurial.i18n import _ |
12 from mercurial.i18n import _ |
13 |
13 |
14 _canloaddefaultcerts = False |
14 _canloaddefaultcerts = False |
|
15 CERT_REQUIRED = ssl.CERT_REQUIRED |
15 try: |
16 try: |
16 CERT_REQUIRED = ssl.CERT_REQUIRED |
17 ssl_context = ssl.SSLContext |
17 try: |
18 _canloaddefaultcerts = util.safehasattr(ssl_context, 'load_default_certs') |
18 ssl_context = ssl.SSLContext |
19 |
19 _canloaddefaultcerts = util.safehasattr(ssl_context, |
20 def wrapsocket(sock, keyfile, certfile, ui, cert_reqs=ssl.CERT_NONE, |
20 'load_default_certs') |
21 ca_certs=None, serverhostname=None): |
21 |
22 # Allow any version of SSL starting with TLSv1 and |
22 def wrapsocket(sock, keyfile, certfile, ui, |
23 # up. Note that specifying TLSv1 here prohibits use of |
23 cert_reqs=ssl.CERT_NONE, |
24 # newer standards (like TLSv1_2), so this is the right way |
24 ca_certs=None, serverhostname=None): |
25 # to do this. Note that in the future it'd be better to |
25 # Allow any version of SSL starting with TLSv1 and |
26 # support using ssl.create_default_context(), which sets |
26 # up. Note that specifying TLSv1 here prohibits use of |
27 # up a bunch of things in smart ways (strong ciphers, |
27 # newer standards (like TLSv1_2), so this is the right way |
28 # protocol versions, etc) and is upgraded by Python |
28 # to do this. Note that in the future it'd be better to |
29 # maintainers for us, but that breaks too many things to |
29 # support using ssl.create_default_context(), which sets |
30 # do it in a hurry. |
30 # up a bunch of things in smart ways (strong ciphers, |
31 sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
31 # protocol versions, etc) and is upgraded by Python |
32 sslcontext.options &= ssl.OP_NO_SSLv2 & ssl.OP_NO_SSLv3 |
32 # maintainers for us, but that breaks too many things to |
33 if certfile is not None: |
33 # do it in a hurry. |
34 def password(): |
34 sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
35 f = keyfile or certfile |
35 sslcontext.options &= ssl.OP_NO_SSLv2 & ssl.OP_NO_SSLv3 |
36 return ui.getpass(_('passphrase for %s: ') % f, '') |
36 if certfile is not None: |
37 sslcontext.load_cert_chain(certfile, keyfile, password) |
37 def password(): |
38 sslcontext.verify_mode = cert_reqs |
38 f = keyfile or certfile |
39 if ca_certs is not None: |
39 return ui.getpass(_('passphrase for %s: ') % f, '') |
40 sslcontext.load_verify_locations(cafile=ca_certs) |
40 sslcontext.load_cert_chain(certfile, keyfile, password) |
41 elif _canloaddefaultcerts: |
41 sslcontext.verify_mode = cert_reqs |
42 sslcontext.load_default_certs() |
42 if ca_certs is not None: |
43 |
43 sslcontext.load_verify_locations(cafile=ca_certs) |
44 sslsocket = sslcontext.wrap_socket(sock, server_hostname=serverhostname) |
44 elif _canloaddefaultcerts: |
45 # check if wrap_socket failed silently because socket had been |
45 sslcontext.load_default_certs() |
46 # closed |
46 |
47 # - see http://bugs.python.org/issue13721 |
47 sslsocket = sslcontext.wrap_socket(sock, |
48 if not sslsocket.cipher(): |
48 server_hostname=serverhostname) |
49 raise util.Abort(_('ssl connection failed')) |
49 # check if wrap_socket failed silently because socket had been |
50 return sslsocket |
50 # closed |
51 except AttributeError: |
51 # - see http://bugs.python.org/issue13721 |
52 def wrapsocket(sock, keyfile, certfile, ui, cert_reqs=ssl.CERT_NONE, |
52 if not sslsocket.cipher(): |
53 ca_certs=None, serverhostname=None): |
53 raise util.Abort(_('ssl connection failed')) |
54 sslsocket = ssl.wrap_socket(sock, keyfile, certfile, |
54 return sslsocket |
55 cert_reqs=cert_reqs, ca_certs=ca_certs, |
55 except AttributeError: |
56 ssl_version=ssl.PROTOCOL_TLSv1) |
56 def wrapsocket(sock, keyfile, certfile, ui, |
57 # check if wrap_socket failed silently because socket had been |
57 cert_reqs=ssl.CERT_NONE, |
58 # closed |
58 ca_certs=None, serverhostname=None): |
59 # - see http://bugs.python.org/issue13721 |
59 sslsocket = ssl.wrap_socket(sock, keyfile, certfile, |
60 if not sslsocket.cipher(): |
60 cert_reqs=cert_reqs, ca_certs=ca_certs, |
61 raise util.Abort(_('ssl connection failed')) |
61 ssl_version=ssl.PROTOCOL_TLSv1) |
62 return sslsocket |
62 # check if wrap_socket failed silently because socket had been |
|
63 # closed |
|
64 # - see http://bugs.python.org/issue13721 |
|
65 if not sslsocket.cipher(): |
|
66 raise util.Abort(_('ssl connection failed')) |
|
67 return sslsocket |
|
68 except ImportError: |
|
69 raise |
|
70 |
63 |
71 def _verifycert(cert, hostname): |
64 def _verifycert(cert, hostname): |
72 '''Verify that cert (in socket.getpeercert() format) matches hostname. |
65 '''Verify that cert (in socket.getpeercert() format) matches hostname. |
73 CRLs is not handled. |
66 CRLs is not handled. |
74 |
67 |