[PATCH 2 of 6] sslutil: move sslkwargs logic into internal function (API)
Gregory Szorc
gregory.szorc at gmail.com
Wed May 25 23:03:51 EDT 2016
# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1464231122 25200
# Wed May 25 19:52:02 2016 -0700
# Node ID f57cb70979b5399f7d5543de268e6eb79fdcd51f
# Parent 62c63aafbff472307fcf4624d63d691f769b4fb2
sslutil: move sslkwargs logic into internal function (API)
As the previous commit documented, sslkwargs() doesn't add any
value since its return is treated as a black box and proxied
to wrapsocket().
We formalize its uselessness by moving its logic into a
new, internal function and make sslkwargs() return an empty
dict.
The certificate arguments that sslkwargs specified have been
removed from wrapsocket() because they should no longer be
set.
diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py
--- a/mercurial/sslutil.py
+++ b/mercurial/sslutil.py
@@ -101,33 +101,76 @@ except AttributeError:
'ca_certs': self._cacerts,
}
if self._supportsciphers:
args['ciphers'] = self._ciphers
return ssl.wrap_socket(socket, **args)
-def wrapsocket(sock, keyfile, certfile, ui, cert_reqs=ssl.CERT_NONE,
- ca_certs=None, serverhostname=None):
+def _determinecertoptions(ui, host):
+ """Determine certificate options for a connections.
+
+ Returns a tuple of (cert_reqs, ca_certs).
+ """
+ # If a host key fingerprint is on file, it is the only thing that matters
+ # and CA certs don't come into play.
+ hostfingerprint = ui.config('hostfingerprints', host)
+ if hostfingerprint:
+ return ssl.CERT_NONE, None
+
+ # The code below sets up CA verification arguments. If --insecure is
+ # used, we don't take CAs into consideration, so return early.
+ if ui.insecureconnections:
+ return ssl.CERT_NONE, None
+
+ cacerts = ui.config('web', 'cacerts')
+
+ # If a value is set in the config, validate against a path and load
+ # and require those certs.
+ if cacerts:
+ cacerts = util.expandpath(cacerts)
+ if not os.path.exists(cacerts):
+ raise error.Abort(_('could not find web.cacerts: %s') % cacerts)
+
+ return ssl.CERT_REQUIRED, cacerts
+
+ # No CAs in config. See if we can load defaults.
+ cacerts = _defaultcacerts()
+
+ # We found an alternate CA bundle to use. Load it.
+ if cacerts:
+ ui.debug('using %s to enable OS X system CA\n' % cacerts)
+ ui.setconfig('web', 'cacerts', cacerts, 'defaultcacerts')
+ return ssl.CERT_REQUIRED, cacerts
+
+ # FUTURE this can disappear once wrapsocket() is secure by default.
+ if _canloaddefaultcerts:
+ return ssl.CERT_REQUIRED, None
+
+ return ssl.CERT_NONE, None
+
+def wrapsocket(sock, keyfile, certfile, ui, serverhostname=None):
"""Add SSL/TLS to a socket.
This is a glorified wrapper for ``ssl.wrap_socket()``. It makes sane
choices based on what security options are available.
In addition to the arguments supported by ``ssl.wrap_socket``, we allow
the following additional arguments:
* serverhostname - The expected hostname of the remote server. If the
server (and client) support SNI, this tells the server which certificate
to use.
"""
if not serverhostname:
raise error.Abort('serverhostname argument is required')
+ cert_reqs, ca_certs = _determinecertoptions(ui, serverhostname)
+
# Despite its name, PROTOCOL_SSLv23 selects the highest protocol
# that both ends support, including TLS protocols. On legacy stacks,
# the highest it likely goes in TLS 1.0. On modern stacks, it can
# support TLS 1.2.
#
# The PROTOCOL_TLSv* constants select a specific TLS version
# only (as opposed to multiple versions). So the method for
# supporting multiple TLS versions is to use PROTOCOL_SSLv23 and
@@ -238,63 +281,17 @@ def _defaultcacerts():
if _plainapplepython():
dummycert = os.path.join(os.path.dirname(__file__), 'dummycert.pem')
if os.path.exists(dummycert):
return dummycert
return None
def sslkwargs(ui, host):
- """Determine arguments to pass to wrapsocket().
-
- ``host`` is the hostname being connected to.
- """
- kws = {}
-
- # If a host key fingerprint is on file, it is the only thing that matters
- # and CA certs don't come into play.
- hostfingerprint = ui.config('hostfingerprints', host)
- if hostfingerprint:
- return kws
-
- # The code below sets up CA verification arguments. If --insecure is
- # used, we don't take CAs into consideration, so return early.
- if ui.insecureconnections:
- return kws
-
- cacerts = ui.config('web', 'cacerts')
-
- # If a value is set in the config, validate against a path and load
- # and require those certs.
- if cacerts:
- cacerts = util.expandpath(cacerts)
- if not os.path.exists(cacerts):
- raise error.Abort(_('could not find web.cacerts: %s') % cacerts)
-
- kws.update({'ca_certs': cacerts,
- 'cert_reqs': ssl.CERT_REQUIRED})
- return kws
-
- # No CAs in config. See if we can load defaults.
- cacerts = _defaultcacerts()
-
- # We found an alternate CA bundle to use. Load it.
- if cacerts:
- ui.debug('using %s to enable OS X system CA\n' % cacerts)
- ui.setconfig('web', 'cacerts', cacerts, 'defaultcacerts')
- kws.update({'ca_certs': cacerts,
- 'cert_reqs': ssl.CERT_REQUIRED})
- return kws
-
- # FUTURE this can disappear once wrapsocket() is secure by default.
- if _canloaddefaultcerts:
- kws['cert_reqs'] = ssl.CERT_REQUIRED
- return kws
-
- return kws
+ return {}
def validatesocket(sock, strict=False):
"""Validate a socket meets security requiremnets.
The passed socket must have been created with ``wrapsocket()``.
"""
host = sock._hgstate['hostname']
ui = sock._hgstate['ui']
More information about the Mercurial-devel
mailing list