Mercurial > public > mercurial-scm > hg
comparison mercurial/sslutil.py @ 25415:21b536f01eda
ssl: prompt passphrase of client key file via ui.getpass() (issue4648)
This is necessary to communicate with third-party tools through command-server
channel. This requires SSLContext backported to Python 2.7.9+.
It doesn't look nice to pass ui by sslkwargs, but I think it is the only way
to do without touching various client codes including httpclient (aka http2).
ui is mandatory if certfile is specified, so it has no default value.
BTW, test-check-commit-hg.t complains that ssl_wrap_socket() has foo_bar
naming. Should I bulk-replace it to sslwrapsocket() ?
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Thu, 07 May 2015 17:15:24 +0900 |
parents | 241d98d84aed |
children | 9d1c61715939 |
comparison
equal
deleted
inserted
replaced
25414:f7ccbc2776b7 | 25415:21b536f01eda |
---|---|
19 try: | 19 try: |
20 ssl_context = ssl.SSLContext | 20 ssl_context = ssl.SSLContext |
21 _canloaddefaultcerts = util.safehasattr(ssl_context, | 21 _canloaddefaultcerts = util.safehasattr(ssl_context, |
22 'load_default_certs') | 22 'load_default_certs') |
23 | 23 |
24 def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=ssl.CERT_NONE, | 24 def ssl_wrap_socket(sock, keyfile, certfile, ui, |
25 cert_reqs=ssl.CERT_NONE, | |
25 ca_certs=None, serverhostname=None): | 26 ca_certs=None, serverhostname=None): |
26 # Allow any version of SSL starting with TLSv1 and | 27 # Allow any version of SSL starting with TLSv1 and |
27 # up. Note that specifying TLSv1 here prohibits use of | 28 # up. Note that specifying TLSv1 here prohibits use of |
28 # newer standards (like TLSv1_2), so this is the right way | 29 # newer standards (like TLSv1_2), so this is the right way |
29 # to do this. Note that in the future it'd be better to | 30 # to do this. Note that in the future it'd be better to |
33 # maintainers for us, but that breaks too many things to | 34 # maintainers for us, but that breaks too many things to |
34 # do it in a hurry. | 35 # do it in a hurry. |
35 sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) | 36 sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) |
36 sslcontext.options &= ssl.OP_NO_SSLv2 & ssl.OP_NO_SSLv3 | 37 sslcontext.options &= ssl.OP_NO_SSLv2 & ssl.OP_NO_SSLv3 |
37 if certfile is not None: | 38 if certfile is not None: |
38 sslcontext.load_cert_chain(certfile, keyfile) | 39 def password(): |
40 f = keyfile or certfile | |
41 return ui.getpass(_('passphrase for %s: ') % f, '') | |
42 sslcontext.load_cert_chain(certfile, keyfile, password) | |
39 sslcontext.verify_mode = cert_reqs | 43 sslcontext.verify_mode = cert_reqs |
40 if ca_certs is not None: | 44 if ca_certs is not None: |
41 sslcontext.load_verify_locations(cafile=ca_certs) | 45 sslcontext.load_verify_locations(cafile=ca_certs) |
42 elif _canloaddefaultcerts: | 46 elif _canloaddefaultcerts: |
43 sslcontext.load_default_certs() | 47 sslcontext.load_default_certs() |
49 # - see http://bugs.python.org/issue13721 | 53 # - see http://bugs.python.org/issue13721 |
50 if not sslsocket.cipher(): | 54 if not sslsocket.cipher(): |
51 raise util.Abort(_('ssl connection failed')) | 55 raise util.Abort(_('ssl connection failed')) |
52 return sslsocket | 56 return sslsocket |
53 except AttributeError: | 57 except AttributeError: |
54 def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=ssl.CERT_NONE, | 58 def ssl_wrap_socket(sock, keyfile, certfile, ui, |
59 cert_reqs=ssl.CERT_NONE, | |
55 ca_certs=None, serverhostname=None): | 60 ca_certs=None, serverhostname=None): |
56 sslsocket = ssl.wrap_socket(sock, keyfile, certfile, | 61 sslsocket = ssl.wrap_socket(sock, keyfile, certfile, |
57 cert_reqs=cert_reqs, ca_certs=ca_certs, | 62 cert_reqs=cert_reqs, ca_certs=ca_certs, |
58 ssl_version=ssl.PROTOCOL_TLSv1) | 63 ssl_version=ssl.PROTOCOL_TLSv1) |
59 # check if wrap_socket failed silently because socket had been | 64 # check if wrap_socket failed silently because socket had been |
65 except ImportError: | 70 except ImportError: |
66 CERT_REQUIRED = 2 | 71 CERT_REQUIRED = 2 |
67 | 72 |
68 import socket, httplib | 73 import socket, httplib |
69 | 74 |
70 def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=CERT_REQUIRED, | 75 def ssl_wrap_socket(sock, keyfile, certfile, ui, |
76 cert_reqs=CERT_REQUIRED, | |
71 ca_certs=None, serverhostname=None): | 77 ca_certs=None, serverhostname=None): |
72 if not util.safehasattr(socket, 'ssl'): | 78 if not util.safehasattr(socket, 'ssl'): |
73 raise util.Abort(_('Python SSL support not found')) | 79 raise util.Abort(_('Python SSL support not found')) |
74 if ca_certs: | 80 if ca_certs: |
75 raise util.Abort(_( | 81 raise util.Abort(_( |
144 if _canloaddefaultcerts: | 150 if _canloaddefaultcerts: |
145 return None | 151 return None |
146 return '!' | 152 return '!' |
147 | 153 |
148 def sslkwargs(ui, host): | 154 def sslkwargs(ui, host): |
149 kws = {} | 155 kws = {'ui': ui} |
150 hostfingerprint = ui.config('hostfingerprints', host) | 156 hostfingerprint = ui.config('hostfingerprints', host) |
151 if hostfingerprint: | 157 if hostfingerprint: |
152 return kws | 158 return kws |
153 cacerts = ui.config('web', 'cacerts') | 159 cacerts = ui.config('web', 'cacerts') |
154 if cacerts == '!': | 160 if cacerts == '!': |