[PATCH V2] sslutil: more robustly detect protocol support

Augie Fackler raf at durin42.com
Mon Jul 18 13:51:43 EDT 2016


On Mon, Jul 18, 2016 at 09:06:00AM -0700, Gregory Szorc wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at gmail.com>
> # Date 1468779391 25200
> #      Sun Jul 17 11:16:31 2016 -0700
> # Node ID 5c24dae37a3c7d6c66aba256ac98621d8aa07f64
> # Parent  953839de96ab574caa40557c542c262286c6287c
> sslutil: more robustly detect protocol support

I'm a huge fan of this, but it looks like this has busted tests
(test-https.t has a server that fails to start?) with /usr/bin/python
on OS X (as that has SSLContext but lacks TLS > 1.0).

>
> The Python ssl module conditionally sets the TLS 1.1 and TLS 1.2
> constants depending on whether HAVE_TLSv1_2 is defined. Yes, these
> are both tied to the same constant (I would think there would be
> separate constants for each version). Perhaps support for TLS 1.1
> and 1.2 were added at the same time and the assumption is that
> OpenSSL either has neither or both. I don't know.
>
> Strictly speaking, we should introduce hghave tests for TLS 1.2 and
> modify tests accordingly. However, I'm inclined to leave things as
> they are because I'm curious what environments don't have TLS 1.2
> in 2016 and want someone to report a bug so we can find and
> erradicate installs/distributions that are shipping an insecure
> Python 2.7.
>
> diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py
> --- a/mercurial/sslutil.py
> +++ b/mercurial/sslutil.py
> @@ -32,16 +32,24 @@ from . import (
>  configprotocols = set([
>      'tls1.0',
>      'tls1.1',
>      'tls1.2',
>  ])
>
>  hassni = getattr(ssl, 'HAS_SNI', False)
>
> +# TLS 1.1 and 1.2 may not be supported if the OpenSSL Python is compiled
> +# against doesn't support them.
> +supportedprotocols = set(['tls1.0'])
> +if util.safehasattr(ssl, 'PROTOCOL_TLSv1_1'):
> +    supportedprotocols.add('tls1.1')
> +if util.safehasattr(ssl, 'PROTOCOL_TLSv1_2'):
> +    supportedprotocols.add('tls1.2')
> +
>  try:
>      # ssl.SSLContext was added in 2.7.9 and presence indicates modern
>      # SSL/TLS features are available.
>      SSLContext = ssl.SSLContext
>      modernssl = True
>      _canloaddefaultcerts = util.safehasattr(SSLContext, 'load_default_certs')
>  except AttributeError:
>      modernssl = False
> @@ -143,25 +151,23 @@ def _hostsettings(ui, hostname):
>      def validateprotocol(protocol, key):
>          if protocol not in configprotocols:
>              raise error.Abort(
>                  _('unsupported protocol from hostsecurity.%s: %s') %
>                  (key, protocol),
>                  hint=_('valid protocols: %s') %
>                       ' '.join(sorted(configprotocols)))
>
> -    # Legacy Python can only do TLS 1.0. We default to TLS 1.1+ where we
> -    # can because TLS 1.0 has known vulnerabilities (like BEAST and POODLE).
> -    # We allow users to downgrade to TLS 1.0+ via config options in case a
> -    # legacy server is encountered.
> -    if modernssl:
> +    # We default to TLS 1.1+ where we can because TLS 1.0 has known
> +    # vulnerabilities (like BEAST and POODLE). We allow users to downgrade to
> +    # TLS 1.0+ via config options in case a legacy server is encountered.
> +    if 'tls1.1' in supportedprotocols:
>          defaultprotocol = 'tls1.1'
>      else:
> -        # Let people on legacy Python versions know they are borderline
> -        # secure.
> +        # Let people know they are borderline secure.
>          # We don't document this config option because we want people to see
>          # the bold warnings on the web site.
>          # internal config: hostsecurity.disabletls10warning
>          if not ui.configbool('hostsecurity', 'disabletls10warning'):
>              ui.warn(_('warning: connecting to %s using legacy security '
>                        'technology (TLS 1.0); see '
>                        'https://mercurial-scm.org/wiki/SecureConnections for '
>                        'more info\n') % hostname)
> @@ -283,17 +289,17 @@ def protocolsettings(protocol):
>      # 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
>      # disable protocols via SSLContext.options and OP_NO_* constants.
>      # However, SSLContext.options doesn't work unless we have the
>      # full/real SSLContext available to us.
> -    if not modernssl:
> +    if supportedprotocols == set(['tls1.0']):
>          if protocol != 'tls1.0':
>              raise error.Abort(_('current Python does not support protocol '
>                                  'setting %s') % protocol,
>                                hint=_('upgrade Python or disable setting since '
>                                       'only TLS 1.0 is supported'))
>
>          return ssl.PROTOCOL_TLSv1, 0
>
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list