Mercurial > hg
changeset 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 | f7ccbc2776b7 |
children | c4a92867c048 |
files | mercurial/sslutil.py mercurial/url.py tests/test-https.t |
diffstat | 3 files changed, 21 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/sslutil.py Thu May 07 17:02:20 2015 +0900 +++ b/mercurial/sslutil.py Thu May 07 17:15:24 2015 +0900 @@ -21,7 +21,8 @@ _canloaddefaultcerts = util.safehasattr(ssl_context, 'load_default_certs') - def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=ssl.CERT_NONE, + def ssl_wrap_socket(sock, keyfile, certfile, ui, + cert_reqs=ssl.CERT_NONE, ca_certs=None, serverhostname=None): # Allow any version of SSL starting with TLSv1 and # up. Note that specifying TLSv1 here prohibits use of @@ -35,7 +36,10 @@ sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) sslcontext.options &= ssl.OP_NO_SSLv2 & ssl.OP_NO_SSLv3 if certfile is not None: - sslcontext.load_cert_chain(certfile, keyfile) + def password(): + f = keyfile or certfile + return ui.getpass(_('passphrase for %s: ') % f, '') + sslcontext.load_cert_chain(certfile, keyfile, password) sslcontext.verify_mode = cert_reqs if ca_certs is not None: sslcontext.load_verify_locations(cafile=ca_certs) @@ -51,7 +55,8 @@ raise util.Abort(_('ssl connection failed')) return sslsocket except AttributeError: - def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=ssl.CERT_NONE, + def ssl_wrap_socket(sock, keyfile, certfile, ui, + cert_reqs=ssl.CERT_NONE, ca_certs=None, serverhostname=None): sslsocket = ssl.wrap_socket(sock, keyfile, certfile, cert_reqs=cert_reqs, ca_certs=ca_certs, @@ -67,7 +72,8 @@ import socket, httplib - def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=CERT_REQUIRED, + def ssl_wrap_socket(sock, keyfile, certfile, ui, + cert_reqs=CERT_REQUIRED, ca_certs=None, serverhostname=None): if not util.safehasattr(socket, 'ssl'): raise util.Abort(_('Python SSL support not found')) @@ -146,7 +152,7 @@ return '!' def sslkwargs(ui, host): - kws = {} + kws = {'ui': ui} hostfingerprint = ui.config('hostfingerprints', host) if hostfingerprint: return kws
--- a/mercurial/url.py Thu May 07 17:02:20 2015 +0900 +++ b/mercurial/url.py Thu May 07 17:15:24 2015 +0900 @@ -175,7 +175,7 @@ self.sock.connect((self.host, self.port)) if _generic_proxytunnel(self): # we do not support client X.509 certificates - self.sock = sslutil.ssl_wrap_socket(self.sock, None, None, + self.sock = sslutil.ssl_wrap_socket(self.sock, None, None, None, serverhostname=self.host) else: keepalive.HTTPConnection.connect(self)
--- a/tests/test-https.t Thu May 07 17:02:20 2015 +0900 +++ b/tests/test-https.t Thu May 07 17:15:24 2015 +0900 @@ -385,10 +385,19 @@ > [auth] > l.prefix = localhost > l.cert = client-cert.pem + > l.key = client-key.pem > EOT $ P=`pwd` hg id https://localhost:$HGPORT/ \ > --config auth.l.key=client-key-decrypted.pem 5fed3813f7f5 + $ printf '1234\n' | env P=`pwd` hg id https://localhost:$HGPORT/ \ + > --config ui.interactive=True --config ui.nontty=True + passphrase for client-key.pem: 5fed3813f7f5 + + $ env P=`pwd` hg id https://localhost:$HGPORT/ + abort: error: * (glob) + [255] + #endif