--- a/mercurial/sslutil.py Sun Oct 06 09:45:02 2019 -0400
+++ b/mercurial/sslutil.py Sun Oct 06 09:48:39 2019 -0400
@@ -36,27 +36,27 @@
# separate code paths depending on support in Python.
configprotocols = {
- 'tls1.0',
- 'tls1.1',
- 'tls1.2',
+ b'tls1.0',
+ b'tls1.1',
+ b'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 = {'tls1.0'}
-if util.safehasattr(ssl, 'PROTOCOL_TLSv1_1'):
- supportedprotocols.add('tls1.1')
-if util.safehasattr(ssl, 'PROTOCOL_TLSv1_2'):
- supportedprotocols.add('tls1.2')
+supportedprotocols = {b'tls1.0'}
+if util.safehasattr(ssl, b'PROTOCOL_TLSv1_1'):
+ supportedprotocols.add(b'tls1.1')
+if util.safehasattr(ssl, b'PROTOCOL_TLSv1_2'):
+ supportedprotocols.add(b'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')
+ _canloaddefaultcerts = util.safehasattr(SSLContext, b'load_default_certs')
except AttributeError:
modernssl = False
_canloaddefaultcerts = False
@@ -87,9 +87,9 @@
def load_verify_locations(self, cafile=None, capath=None, cadata=None):
if capath:
- raise error.Abort(_('capath not supported'))
+ raise error.Abort(_(b'capath not supported'))
if cadata:
- raise error.Abort(_('cadata not supported'))
+ raise error.Abort(_(b'cadata not supported'))
self._cacerts = cafile
@@ -123,175 +123,182 @@
s = {
# Whether we should attempt to load default/available CA certs
# if an explicit ``cafile`` is not defined.
- 'allowloaddefaultcerts': True,
+ b'allowloaddefaultcerts': True,
# List of 2-tuple of (hash algorithm, hash).
- 'certfingerprints': [],
+ b'certfingerprints': [],
# Path to file containing concatenated CA certs. Used by
# SSLContext.load_verify_locations().
- 'cafile': None,
+ b'cafile': None,
# Whether certificate verification should be disabled.
- 'disablecertverification': False,
+ b'disablecertverification': False,
# Whether the legacy [hostfingerprints] section has data for this host.
- 'legacyfingerprint': False,
+ b'legacyfingerprint': False,
# PROTOCOL_* constant to use for SSLContext.__init__.
- 'protocol': None,
+ b'protocol': None,
# String representation of minimum protocol to be used for UI
# presentation.
- 'protocolui': None,
+ b'protocolui': None,
# ssl.CERT_* constant used by SSLContext.verify_mode.
- 'verifymode': None,
+ b'verifymode': None,
# Defines extra ssl.OP* bitwise options to set.
- 'ctxoptions': None,
+ b'ctxoptions': None,
# OpenSSL Cipher List to use (instead of default).
- 'ciphers': None,
+ b'ciphers': None,
}
# Allow minimum TLS protocol to be specified in the config.
def validateprotocol(protocol, key):
if protocol not in configprotocols:
raise error.Abort(
- _('unsupported protocol from hostsecurity.%s: %s')
+ _(b'unsupported protocol from hostsecurity.%s: %s')
% (key, protocol),
- hint=_('valid protocols: %s')
- % ' '.join(sorted(configprotocols)),
+ hint=_(b'valid protocols: %s')
+ % b' '.join(sorted(configprotocols)),
)
# 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'
+ if b'tls1.1' in supportedprotocols:
+ defaultprotocol = b'tls1.1'
else:
# 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'):
+ if not ui.configbool(b'hostsecurity', b'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'
+ b'warning: connecting to %s using legacy security '
+ b'technology (TLS 1.0); see '
+ b'https://mercurial-scm.org/wiki/SecureConnections for '
+ b'more info\n'
)
% bhostname
)
- defaultprotocol = 'tls1.0'
+ defaultprotocol = b'tls1.0'
- key = 'minimumprotocol'
- protocol = ui.config('hostsecurity', key, defaultprotocol)
+ key = b'minimumprotocol'
+ protocol = ui.config(b'hostsecurity', key, defaultprotocol)
validateprotocol(protocol, key)
- key = '%s:minimumprotocol' % bhostname
- protocol = ui.config('hostsecurity', key, protocol)
+ key = b'%s:minimumprotocol' % bhostname
+ protocol = ui.config(b'hostsecurity', key, protocol)
validateprotocol(protocol, key)
# If --insecure is used, we allow the use of TLS 1.0 despite config options.
# We always print a "connection security to %s is disabled..." message when
# --insecure is used. So no need to print anything more here.
if ui.insecureconnections:
- protocol = 'tls1.0'
-
- s['protocol'], s['ctxoptions'], s['protocolui'] = protocolsettings(protocol)
+ protocol = b'tls1.0'
- ciphers = ui.config('hostsecurity', 'ciphers')
- ciphers = ui.config('hostsecurity', '%s:ciphers' % bhostname, ciphers)
- s['ciphers'] = ciphers
+ s[b'protocol'], s[b'ctxoptions'], s[b'protocolui'] = protocolsettings(
+ protocol
+ )
+
+ ciphers = ui.config(b'hostsecurity', b'ciphers')
+ ciphers = ui.config(b'hostsecurity', b'%s:ciphers' % bhostname, ciphers)
+ s[b'ciphers'] = ciphers
# Look for fingerprints in [hostsecurity] section. Value is a list
# of <alg>:<fingerprint> strings.
- fingerprints = ui.configlist('hostsecurity', '%s:fingerprints' % bhostname)
+ fingerprints = ui.configlist(
+ b'hostsecurity', b'%s:fingerprints' % bhostname
+ )
for fingerprint in fingerprints:
- if not (fingerprint.startswith(('sha1:', 'sha256:', 'sha512:'))):
+ if not (fingerprint.startswith((b'sha1:', b'sha256:', b'sha512:'))):
raise error.Abort(
- _('invalid fingerprint for %s: %s') % (bhostname, fingerprint),
- hint=_('must begin with "sha1:", "sha256:", ' 'or "sha512:"'),
+ _(b'invalid fingerprint for %s: %s') % (bhostname, fingerprint),
+ hint=_(b'must begin with "sha1:", "sha256:", ' b'or "sha512:"'),
)
- alg, fingerprint = fingerprint.split(':', 1)
- fingerprint = fingerprint.replace(':', '').lower()
- s['certfingerprints'].append((alg, fingerprint))
+ alg, fingerprint = fingerprint.split(b':', 1)
+ fingerprint = fingerprint.replace(b':', b'').lower()
+ s[b'certfingerprints'].append((alg, fingerprint))
# Fingerprints from [hostfingerprints] are always SHA-1.
- for fingerprint in ui.configlist('hostfingerprints', bhostname):
- fingerprint = fingerprint.replace(':', '').lower()
- s['certfingerprints'].append(('sha1', fingerprint))
- s['legacyfingerprint'] = True
+ for fingerprint in ui.configlist(b'hostfingerprints', bhostname):
+ fingerprint = fingerprint.replace(b':', b'').lower()
+ s[b'certfingerprints'].append((b'sha1', fingerprint))
+ s[b'legacyfingerprint'] = True
# If a host cert fingerprint is defined, it is the only thing that
# matters. No need to validate CA certs.
- if s['certfingerprints']:
- s['verifymode'] = ssl.CERT_NONE
- s['allowloaddefaultcerts'] = False
+ if s[b'certfingerprints']:
+ s[b'verifymode'] = ssl.CERT_NONE
+ s[b'allowloaddefaultcerts'] = False
# If --insecure is used, don't take CAs into consideration.
elif ui.insecureconnections:
- s['disablecertverification'] = True
- s['verifymode'] = ssl.CERT_NONE
- s['allowloaddefaultcerts'] = False
+ s[b'disablecertverification'] = True
+ s[b'verifymode'] = ssl.CERT_NONE
+ s[b'allowloaddefaultcerts'] = False
- if ui.configbool('devel', 'disableloaddefaultcerts'):
- s['allowloaddefaultcerts'] = False
+ if ui.configbool(b'devel', b'disableloaddefaultcerts'):
+ s[b'allowloaddefaultcerts'] = False
# If both fingerprints and a per-host ca file are specified, issue a warning
# because users should not be surprised about what security is or isn't
# being performed.
- cafile = ui.config('hostsecurity', '%s:verifycertsfile' % bhostname)
- if s['certfingerprints'] and cafile:
+ cafile = ui.config(b'hostsecurity', b'%s:verifycertsfile' % bhostname)
+ if s[b'certfingerprints'] and cafile:
ui.warn(
_(
- '(hostsecurity.%s:verifycertsfile ignored when host '
- 'fingerprints defined; using host fingerprints for '
- 'verification)\n'
+ b'(hostsecurity.%s:verifycertsfile ignored when host '
+ b'fingerprints defined; using host fingerprints for '
+ b'verification)\n'
)
% bhostname
)
# Try to hook up CA certificate validation unless something above
# makes it not necessary.
- if s['verifymode'] is None:
+ if s[b'verifymode'] is None:
# Look at per-host ca file first.
if cafile:
cafile = util.expandpath(cafile)
if not os.path.exists(cafile):
raise error.Abort(
- _('path specified by %s does not exist: %s')
- % ('hostsecurity.%s:verifycertsfile' % (bhostname,), cafile)
+ _(b'path specified by %s does not exist: %s')
+ % (
+ b'hostsecurity.%s:verifycertsfile' % (bhostname,),
+ cafile,
+ )
)
- s['cafile'] = cafile
+ s[b'cafile'] = cafile
else:
# Find global certificates file in config.
- cafile = ui.config('web', 'cacerts')
+ cafile = ui.config(b'web', b'cacerts')
if cafile:
cafile = util.expandpath(cafile)
if not os.path.exists(cafile):
raise error.Abort(
- _('could not find web.cacerts: %s') % cafile
+ _(b'could not find web.cacerts: %s') % cafile
)
- elif s['allowloaddefaultcerts']:
+ elif s[b'allowloaddefaultcerts']:
# CAs not defined in config. Try to find system bundles.
cafile = _defaultcacerts(ui)
if cafile:
- ui.debug('using %s for CA file\n' % cafile)
+ ui.debug(b'using %s for CA file\n' % cafile)
- s['cafile'] = cafile
+ s[b'cafile'] = cafile
# Require certificate validation if CA certs are being loaded and
# verification hasn't been disabled above.
- if cafile or (_canloaddefaultcerts and s['allowloaddefaultcerts']):
- s['verifymode'] = ssl.CERT_REQUIRED
+ if cafile or (_canloaddefaultcerts and s[b'allowloaddefaultcerts']):
+ s[b'verifymode'] = ssl.CERT_REQUIRED
else:
# At this point we don't have a fingerprint, aren't being
# explicitly insecure, and can't load CA certs. Connecting
# is insecure. We allow the connection and abort during
# validation (once we have the fingerprint to print to the
# user).
- s['verifymode'] = ssl.CERT_NONE
+ s[b'verifymode'] = ssl.CERT_NONE
- assert s['protocol'] is not None
- assert s['ctxoptions'] is not None
- assert s['verifymode'] is not None
+ assert s[b'protocol'] is not None
+ assert s[b'ctxoptions'] is not None
+ assert s[b'verifymode'] is not None
return s
@@ -304,7 +311,7 @@
of the ``minimumprotocol`` config option equivalent.
"""
if protocol not in configprotocols:
- raise ValueError('protocol value not supported: %s' % protocol)
+ raise ValueError(b'protocol value not supported: %s' % protocol)
# Despite its name, PROTOCOL_SSLv23 selects the highest protocol
# that both ends support, including TLS protocols. On legacy stacks,
@@ -317,18 +324,18 @@
# 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 supportedprotocols == {'tls1.0'}:
- if protocol != 'tls1.0':
+ if supportedprotocols == {b'tls1.0'}:
+ if protocol != b'tls1.0':
raise error.Abort(
- _('current Python does not support protocol ' 'setting %s')
+ _(b'current Python does not support protocol ' b'setting %s')
% protocol,
hint=_(
- 'upgrade Python or disable setting since '
- 'only TLS 1.0 is supported'
+ b'upgrade Python or disable setting since '
+ b'only TLS 1.0 is supported'
),
)
- return ssl.PROTOCOL_TLSv1, 0, 'tls1.0'
+ return ssl.PROTOCOL_TLSv1, 0, b'tls1.0'
# WARNING: returned options don't work unless the modern ssl module
# is available. Be careful when adding options here.
@@ -336,15 +343,15 @@
# SSLv2 and SSLv3 are broken. We ban them outright.
options = ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3
- if protocol == 'tls1.0':
+ if protocol == b'tls1.0':
# Defaults above are to use TLS 1.0+
pass
- elif protocol == 'tls1.1':
+ elif protocol == b'tls1.1':
options |= ssl.OP_NO_TLSv1
- elif protocol == 'tls1.2':
+ elif protocol == b'tls1.2':
options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
else:
- raise error.Abort(_('this should not happen'))
+ raise error.Abort(_(b'this should not happen'))
# Prevent CRIME.
# There is no guarantee this attribute is defined on the module.
@@ -367,7 +374,7 @@
to use.
"""
if not serverhostname:
- raise error.Abort(_('serverhostname argument is required'))
+ raise error.Abort(_(b'serverhostname argument is required'))
if b'SSLKEYLOGFILE' in encoding.environ:
try:
@@ -388,11 +395,11 @@
for f in (keyfile, certfile):
if f and not os.path.exists(f):
raise error.Abort(
- _('certificate file (%s) does not exist; cannot connect to %s')
+ _(b'certificate file (%s) does not exist; cannot connect to %s')
% (f, pycompat.bytesurl(serverhostname)),
hint=_(
- 'restore missing file or fix references '
- 'in Mercurial config'
+ b'restore missing file or fix references '
+ b'in Mercurial config'
),
)
@@ -405,48 +412,48 @@
# bundle with a specific CA cert removed. If the system/default CA bundle
# is loaded and contains that removed CA, you've just undone the user's
# choice.
- sslcontext = SSLContext(settings['protocol'])
+ sslcontext = SSLContext(settings[b'protocol'])
# This is a no-op unless using modern ssl.
- sslcontext.options |= settings['ctxoptions']
+ sslcontext.options |= settings[b'ctxoptions']
# This still works on our fake SSLContext.
- sslcontext.verify_mode = settings['verifymode']
+ sslcontext.verify_mode = settings[b'verifymode']
- if settings['ciphers']:
+ if settings[b'ciphers']:
try:
- sslcontext.set_ciphers(pycompat.sysstr(settings['ciphers']))
+ sslcontext.set_ciphers(pycompat.sysstr(settings[b'ciphers']))
except ssl.SSLError as e:
raise error.Abort(
- _('could not set ciphers: %s')
+ _(b'could not set ciphers: %s')
% stringutil.forcebytestr(e.args[0]),
- hint=_('change cipher string (%s) in config')
- % settings['ciphers'],
+ hint=_(b'change cipher string (%s) in config')
+ % settings[b'ciphers'],
)
if certfile is not None:
def password():
f = keyfile or certfile
- return ui.getpass(_('passphrase for %s: ') % f, '')
+ return ui.getpass(_(b'passphrase for %s: ') % f, b'')
sslcontext.load_cert_chain(certfile, keyfile, password)
- if settings['cafile'] is not None:
+ if settings[b'cafile'] is not None:
try:
- sslcontext.load_verify_locations(cafile=settings['cafile'])
+ sslcontext.load_verify_locations(cafile=settings[b'cafile'])
except ssl.SSLError as e:
if len(e.args) == 1: # pypy has different SSLError args
msg = e.args[0]
else:
msg = e.args[1]
raise error.Abort(
- _('error loading CA file %s: %s')
- % (settings['cafile'], stringutil.forcebytestr(msg)),
- hint=_('file is empty or malformed?'),
+ _(b'error loading CA file %s: %s')
+ % (settings[b'cafile'], stringutil.forcebytestr(msg)),
+ hint=_(b'file is empty or malformed?'),
)
caloaded = True
- elif settings['allowloaddefaultcerts']:
+ elif settings[b'allowloaddefaultcerts']:
# This is a no-op on old Python.
sslcontext.load_default_certs()
caloaded = True
@@ -468,24 +475,24 @@
try:
if (
caloaded
- and settings['verifymode'] == ssl.CERT_REQUIRED
+ and settings[b'verifymode'] == ssl.CERT_REQUIRED
and modernssl
and not sslcontext.get_ca_certs()
):
ui.warn(
_(
- '(an attempt was made to load CA certificates but '
- 'none were loaded; see '
- 'https://mercurial-scm.org/wiki/SecureConnections '
- 'for how to configure Mercurial to avoid this '
- 'error)\n'
+ b'(an attempt was made to load CA certificates but '
+ b'none were loaded; see '
+ b'https://mercurial-scm.org/wiki/SecureConnections '
+ b'for how to configure Mercurial to avoid this '
+ b'error)\n'
)
)
except ssl.SSLError:
pass
# Try to print more helpful error messages for known failures.
- if util.safehasattr(e, 'reason'):
+ if util.safehasattr(e, b'reason'):
# This error occurs when the client and server don't share a
# common/supported SSL/TLS protocol. We've disabled SSLv2 and SSLv3
# outright. Hopefully the reason for this error is that we require
@@ -493,36 +500,36 @@
# reason, try to emit an actionable warning.
if e.reason == r'UNSUPPORTED_PROTOCOL':
# We attempted TLS 1.0+.
- if settings['protocolui'] == 'tls1.0':
+ if settings[b'protocolui'] == b'tls1.0':
# We support more than just TLS 1.0+. If this happens,
# the likely scenario is either the client or the server
# is really old. (e.g. server doesn't support TLS 1.0+ or
# client doesn't support modern TLS versions introduced
# several years from when this comment was written).
- if supportedprotocols != {'tls1.0'}:
+ if supportedprotocols != {b'tls1.0'}:
ui.warn(
_(
- '(could not communicate with %s using security '
- 'protocols %s; if you are using a modern Mercurial '
- 'version, consider contacting the operator of this '
- 'server; see '
- 'https://mercurial-scm.org/wiki/SecureConnections '
- 'for more info)\n'
+ b'(could not communicate with %s using security '
+ b'protocols %s; if you are using a modern Mercurial '
+ b'version, consider contacting the operator of this '
+ b'server; see '
+ b'https://mercurial-scm.org/wiki/SecureConnections '
+ b'for more info)\n'
)
% (
pycompat.bytesurl(serverhostname),
- ', '.join(sorted(supportedprotocols)),
+ b', '.join(sorted(supportedprotocols)),
)
)
else:
ui.warn(
_(
- '(could not communicate with %s using TLS 1.0; the '
- 'likely cause of this is the server no longer '
- 'supports TLS 1.0 because it has known security '
- 'vulnerabilities; see '
- 'https://mercurial-scm.org/wiki/SecureConnections '
- 'for more info)\n'
+ b'(could not communicate with %s using TLS 1.0; the '
+ b'likely cause of this is the server no longer '
+ b'supports TLS 1.0 because it has known security '
+ b'vulnerabilities; see '
+ b'https://mercurial-scm.org/wiki/SecureConnections '
+ b'for more info)\n'
)
% pycompat.bytesurl(serverhostname)
)
@@ -533,30 +540,30 @@
# offer.
ui.warn(
_(
- '(could not negotiate a common security protocol (%s+) '
- 'with %s; the likely cause is Mercurial is configured '
- 'to be more secure than the server can support)\n'
+ b'(could not negotiate a common security protocol (%s+) '
+ b'with %s; the likely cause is Mercurial is configured '
+ b'to be more secure than the server can support)\n'
)
% (
- settings['protocolui'],
+ settings[b'protocolui'],
pycompat.bytesurl(serverhostname),
)
)
ui.warn(
_(
- '(consider contacting the operator of this '
- 'server and ask them to support modern TLS '
- 'protocol versions; or, set '
- 'hostsecurity.%s:minimumprotocol=tls1.0 to allow '
- 'use of legacy, less secure protocols when '
- 'communicating with this server)\n'
+ b'(consider contacting the operator of this '
+ b'server and ask them to support modern TLS '
+ b'protocol versions; or, set '
+ b'hostsecurity.%s:minimumprotocol=tls1.0 to allow '
+ b'use of legacy, less secure protocols when '
+ b'communicating with this server)\n'
)
% pycompat.bytesurl(serverhostname)
)
ui.warn(
_(
- '(see https://mercurial-scm.org/wiki/SecureConnections '
- 'for more info)\n'
+ b'(see https://mercurial-scm.org/wiki/SecureConnections '
+ b'for more info)\n'
)
)
@@ -566,8 +573,8 @@
ui.warn(
_(
- '(the full certificate chain may not be available '
- 'locally; see "hg help debugssl")\n'
+ b'(the full certificate chain may not be available '
+ b'locally; see "hg help debugssl")\n'
)
)
raise
@@ -576,13 +583,13 @@
# closed
# - see http://bugs.python.org/issue13721
if not sslsocket.cipher():
- raise error.Abort(_('ssl connection failed'))
+ raise error.Abort(_(b'ssl connection failed'))
sslsocket._hgstate = {
- 'caloaded': caloaded,
- 'hostname': serverhostname,
- 'settings': settings,
- 'ui': ui,
+ b'caloaded': caloaded,
+ b'hostname': serverhostname,
+ b'settings': settings,
+ b'ui': ui,
}
return sslsocket
@@ -608,27 +615,27 @@
for f in (certfile, keyfile, cafile):
if f and not os.path.exists(f):
raise error.Abort(
- _('referenced certificate file (%s) does not ' 'exist') % f
+ _(b'referenced certificate file (%s) does not ' b'exist') % f
)
- protocol, options, _protocolui = protocolsettings('tls1.0')
+ protocol, options, _protocolui = protocolsettings(b'tls1.0')
# This config option is intended for use in tests only. It is a giant
# footgun to kill security. Don't define it.
- exactprotocol = ui.config('devel', 'serverexactprotocol')
- if exactprotocol == 'tls1.0':
+ exactprotocol = ui.config(b'devel', b'serverexactprotocol')
+ if exactprotocol == b'tls1.0':
protocol = ssl.PROTOCOL_TLSv1
- elif exactprotocol == 'tls1.1':
- if 'tls1.1' not in supportedprotocols:
- raise error.Abort(_('TLS 1.1 not supported by this Python'))
+ elif exactprotocol == b'tls1.1':
+ if b'tls1.1' not in supportedprotocols:
+ raise error.Abort(_(b'TLS 1.1 not supported by this Python'))
protocol = ssl.PROTOCOL_TLSv1_1
- elif exactprotocol == 'tls1.2':
- if 'tls1.2' not in supportedprotocols:
- raise error.Abort(_('TLS 1.2 not supported by this Python'))
+ elif exactprotocol == b'tls1.2':
+ if b'tls1.2' not in supportedprotocols:
+ raise error.Abort(_(b'TLS 1.2 not supported by this Python'))
protocol = ssl.PROTOCOL_TLSv1_2
elif exactprotocol:
raise error.Abort(
- _('invalid value for serverexactprotocol: %s') % exactprotocol
+ _(b'invalid value for serverexactprotocol: %s') % exactprotocol
)
if modernssl:
@@ -643,7 +650,7 @@
sslcontext.options |= getattr(ssl, 'OP_SINGLE_ECDH_USE', 0)
# Use the list of more secure ciphers if found in the ssl module.
- if util.safehasattr(ssl, '_RESTRICTED_SERVER_CIPHERS'):
+ if util.safehasattr(ssl, b'_RESTRICTED_SERVER_CIPHERS'):
sslcontext.options |= getattr(ssl, 'OP_CIPHER_SERVER_PREFERENCE', 0)
sslcontext.set_ciphers(ssl._RESTRICTED_SERVER_CIPHERS)
else:
@@ -681,13 +688,13 @@
dn = pycompat.bytesurl(dn)
hostname = pycompat.bytesurl(hostname)
- pieces = dn.split('.')
+ pieces = dn.split(b'.')
leftmost = pieces[0]
remainder = pieces[1:]
- wildcards = leftmost.count('*')
+ wildcards = leftmost.count(b'*')
if wildcards > maxwildcards:
raise wildcarderror(
- _('too many wildcards in certificate DNS name: %s') % dn
+ _(b'too many wildcards in certificate DNS name: %s') % dn
)
# speed up common case w/o wildcards
@@ -697,11 +704,11 @@
# RFC 6125, section 6.4.3, subitem 1.
# The client SHOULD NOT attempt to match a presented identifier in which
# the wildcard character comprises a label other than the left-most label.
- if leftmost == '*':
+ if leftmost == b'*':
# When '*' is a fragment by itself, it matches a non-empty dotless
# fragment.
- pats.append('[^.]+')
- elif leftmost.startswith('xn--') or hostname.startswith('xn--'):
+ pats.append(b'[^.]+')
+ elif leftmost.startswith(b'xn--') or hostname.startswith(b'xn--'):
# RFC 6125, section 6.4.3, subitem 3.
# The client SHOULD NOT attempt to match a presented identifier
# where the wildcard character is embedded within an A-label or
@@ -709,7 +716,7 @@
pats.append(stringutil.reescape(leftmost))
else:
# Otherwise, '*' matches any dotless string, e.g. www*
- pats.append(stringutil.reescape(leftmost).replace(br'\*', '[^.]*'))
+ pats.append(stringutil.reescape(leftmost).replace(br'\*', b'[^.]*'))
# add the remaining fragments, ignore any wildcards
for frag in remainder:
@@ -726,7 +733,7 @@
Returns error message if any problems are found and None on success.
'''
if not cert:
- return _('no certificate received')
+ return _(b'no certificate received')
dnsnames = []
san = cert.get(r'subjectAltName', [])
@@ -751,7 +758,7 @@
try:
value = value.encode('ascii')
except UnicodeEncodeError:
- return _('IDN in certificate not supported')
+ return _(b'IDN in certificate not supported')
try:
if _dnsnamematch(value, hostname):
@@ -763,11 +770,11 @@
dnsnames = [pycompat.bytesurl(d) for d in dnsnames]
if len(dnsnames) > 1:
- return _('certificate is for %s') % ', '.join(dnsnames)
+ return _(b'certificate is for %s') % b', '.join(dnsnames)
elif len(dnsnames) == 1:
- return _('certificate is for %s') % dnsnames[0]
+ return _(b'certificate is for %s') % dnsnames[0]
else:
- return _('no commonName or subjectAltName found in certificate')
+ return _(b'no commonName or subjectAltName found in certificate')
def _plainapplepython():
@@ -785,16 +792,16 @@
):
return False
exe = os.path.realpath(pycompat.sysexecutable).lower()
- return exe.startswith('/usr/bin/python') or exe.startswith(
- '/system/library/frameworks/python.framework/'
+ return exe.startswith(b'/usr/bin/python') or exe.startswith(
+ b'/system/library/frameworks/python.framework/'
)
_systemcacertpaths = [
# RHEL, CentOS, and Fedora
- '/etc/pki/tls/certs/ca-bundle.trust.crt',
+ b'/etc/pki/tls/certs/ca-bundle.trust.crt',
# Debian, Ubuntu, Gentoo
- '/etc/ssl/certs/ca-certificates.crt',
+ b'/etc/ssl/certs/ca-certificates.crt',
]
@@ -815,7 +822,7 @@
certs = certifi.where()
if os.path.exists(certs):
- ui.debug('using ca certificates from certifi\n')
+ ui.debug(b'using ca certificates from certifi\n')
return pycompat.fsencode(certs)
except (ImportError, AttributeError):
pass
@@ -829,9 +836,9 @@
if not _canloaddefaultcerts:
ui.warn(
_(
- '(unable to load Windows CA certificates; see '
- 'https://mercurial-scm.org/wiki/SecureConnections for '
- 'how to configure Mercurial to avoid this message)\n'
+ b'(unable to load Windows CA certificates; see '
+ b'https://mercurial-scm.org/wiki/SecureConnections for '
+ b'how to configure Mercurial to avoid this message)\n'
)
)
@@ -842,7 +849,7 @@
# trick.
if _plainapplepython():
dummycert = os.path.join(
- os.path.dirname(pycompat.fsencode(__file__)), 'dummycert.pem'
+ os.path.dirname(pycompat.fsencode(__file__)), b'dummycert.pem'
)
if os.path.exists(dummycert):
return dummycert
@@ -856,9 +863,9 @@
if not _canloaddefaultcerts:
ui.warn(
_(
- '(unable to load CA certificates; see '
- 'https://mercurial-scm.org/wiki/SecureConnections for '
- 'how to configure Mercurial to avoid this message)\n'
+ b'(unable to load CA certificates; see '
+ b'https://mercurial-scm.org/wiki/SecureConnections for '
+ b'how to configure Mercurial to avoid this message)\n'
)
)
return None
@@ -880,12 +887,12 @@
if os.path.isfile(path):
ui.warn(
_(
- '(using CA certificates from %s; if you see this '
- 'message, your Mercurial install is not properly '
- 'configured; see '
- 'https://mercurial-scm.org/wiki/SecureConnections '
- 'for how to configure Mercurial to avoid this '
- 'message)\n'
+ b'(using CA certificates from %s; if you see this '
+ b'message, your Mercurial install is not properly '
+ b'configured; see '
+ b'https://mercurial-scm.org/wiki/SecureConnections '
+ b'for how to configure Mercurial to avoid this '
+ b'message)\n'
)
% path
)
@@ -893,9 +900,9 @@
ui.warn(
_(
- '(unable to load CA certificates; see '
- 'https://mercurial-scm.org/wiki/SecureConnections for '
- 'how to configure Mercurial to avoid this message)\n'
+ b'(unable to load CA certificates; see '
+ b'https://mercurial-scm.org/wiki/SecureConnections for '
+ b'how to configure Mercurial to avoid this message)\n'
)
)
@@ -907,23 +914,23 @@
The passed socket must have been created with ``wrapsocket()``.
"""
- shost = sock._hgstate['hostname']
+ shost = sock._hgstate[b'hostname']
host = pycompat.bytesurl(shost)
- ui = sock._hgstate['ui']
- settings = sock._hgstate['settings']
+ ui = sock._hgstate[b'ui']
+ settings = sock._hgstate[b'settings']
try:
peercert = sock.getpeercert(True)
peercert2 = sock.getpeercert()
except AttributeError:
- raise error.Abort(_('%s ssl connection error') % host)
+ raise error.Abort(_(b'%s ssl connection error') % host)
if not peercert:
raise error.Abort(
- _('%s certificate error: ' 'no certificate received') % host
+ _(b'%s certificate error: ' b'no certificate received') % host
)
- if settings['disablecertverification']:
+ if settings[b'disablecertverification']:
# We don't print the certificate fingerprint because it shouldn't
# be necessary: if the user requested certificate verification be
# disabled, they presumably already saw a message about the inability
@@ -932,9 +939,9 @@
# value.
ui.warn(
_(
- 'warning: connection security to %s is disabled per current '
- 'settings; communication is susceptible to eavesdropping '
- 'and tampering\n'
+ b'warning: connection security to %s is disabled per current '
+ b'settings; communication is susceptible to eavesdropping '
+ b'and tampering\n'
)
% host
)
@@ -943,63 +950,63 @@
# If a certificate fingerprint is pinned, use it and only it to
# validate the remote cert.
peerfingerprints = {
- 'sha1': node.hex(hashlib.sha1(peercert).digest()),
- 'sha256': node.hex(hashlib.sha256(peercert).digest()),
- 'sha512': node.hex(hashlib.sha512(peercert).digest()),
+ b'sha1': node.hex(hashlib.sha1(peercert).digest()),
+ b'sha256': node.hex(hashlib.sha256(peercert).digest()),
+ b'sha512': node.hex(hashlib.sha512(peercert).digest()),
}
def fmtfingerprint(s):
- return ':'.join([s[x : x + 2] for x in range(0, len(s), 2)])
+ return b':'.join([s[x : x + 2] for x in range(0, len(s), 2)])
- nicefingerprint = 'sha256:%s' % fmtfingerprint(peerfingerprints['sha256'])
+ nicefingerprint = b'sha256:%s' % fmtfingerprint(peerfingerprints[b'sha256'])
- if settings['certfingerprints']:
- for hash, fingerprint in settings['certfingerprints']:
+ if settings[b'certfingerprints']:
+ for hash, fingerprint in settings[b'certfingerprints']:
if peerfingerprints[hash].lower() == fingerprint:
ui.debug(
- '%s certificate matched fingerprint %s:%s\n'
+ b'%s certificate matched fingerprint %s:%s\n'
% (host, hash, fmtfingerprint(fingerprint))
)
- if settings['legacyfingerprint']:
+ if settings[b'legacyfingerprint']:
ui.warn(
_(
- '(SHA-1 fingerprint for %s found in legacy '
- '[hostfingerprints] section; '
- 'if you trust this fingerprint, remove the old '
- 'SHA-1 fingerprint from [hostfingerprints] and '
- 'add the following entry to the new '
- '[hostsecurity] section: %s:fingerprints=%s)\n'
+ b'(SHA-1 fingerprint for %s found in legacy '
+ b'[hostfingerprints] section; '
+ b'if you trust this fingerprint, remove the old '
+ b'SHA-1 fingerprint from [hostfingerprints] and '
+ b'add the following entry to the new '
+ b'[hostsecurity] section: %s:fingerprints=%s)\n'
)
% (host, host, nicefingerprint)
)
return
# Pinned fingerprint didn't match. This is a fatal error.
- if settings['legacyfingerprint']:
- section = 'hostfingerprint'
- nice = fmtfingerprint(peerfingerprints['sha1'])
+ if settings[b'legacyfingerprint']:
+ section = b'hostfingerprint'
+ nice = fmtfingerprint(peerfingerprints[b'sha1'])
else:
- section = 'hostsecurity'
- nice = '%s:%s' % (hash, fmtfingerprint(peerfingerprints[hash]))
+ section = b'hostsecurity'
+ nice = b'%s:%s' % (hash, fmtfingerprint(peerfingerprints[hash]))
raise error.Abort(
- _('certificate for %s has unexpected ' 'fingerprint %s')
+ _(b'certificate for %s has unexpected ' b'fingerprint %s')
% (host, nice),
- hint=_('check %s configuration') % section,
+ hint=_(b'check %s configuration') % section,
)
# Security is enabled but no CAs are loaded. We can't establish trust
# for the cert so abort.
- if not sock._hgstate['caloaded']:
+ if not sock._hgstate[b'caloaded']:
raise error.Abort(
_(
- 'unable to verify security of %s (no loaded CA certificates); '
- 'refusing to connect'
+ b'unable to verify security of %s (no loaded CA certificates); '
+ b'refusing to connect'
)
% host,
hint=_(
- 'see https://mercurial-scm.org/wiki/SecureConnections for '
- 'how to configure Mercurial to avoid this error or set '
- 'hostsecurity.%s:fingerprints=%s to trust this server'
+ b'see https://mercurial-scm.org/wiki/SecureConnections for '
+ b'how to configure Mercurial to avoid this error or set '
+ b'hostsecurity.%s:fingerprints=%s to trust this server'
)
% (host, nicefingerprint),
)
@@ -1007,11 +1014,11 @@
msg = _verifycert(peercert2, shost)
if msg:
raise error.Abort(
- _('%s certificate error: %s') % (host, msg),
+ _(b'%s certificate error: %s') % (host, msg),
hint=_(
- 'set hostsecurity.%s:certfingerprints=%s '
- 'config setting or use --insecure to connect '
- 'insecurely'
+ b'set hostsecurity.%s:certfingerprints=%s '
+ b'config setting or use --insecure to connect '
+ b'insecurely'
)
% (host, nicefingerprint),
)