Submitter | Gregory Szorc |
---|---|
Date | July 20, 2016, 4:31 a.m. |
Message ID | <139d8ab2ebb7368d1dc7.1468989116@ubuntu-vm-main> |
Download | mbox | patch |
Permalink | /patch/15964/ |
State | Accepted |
Headers | show |
Comments
On Tue, Jul 19, 2016 at 09:31:56PM -0700, Gregory Szorc wrote: > # HG changeset patch > # User Gregory Szorc <gregory.szorc@gmail.com> > # Date 1468987798 25200 > # Tue Jul 19 21:09:58 2016 -0700 > # Branch stable > # Node ID 139d8ab2ebb7368d1dc78e18f27b63df483b4e31 > # Parent 925cb3b2baebcbf8f0498f2a7e7cbd6610732cbb > sslutil: improve messaging around unsupported protocols (issue5303) Queued these for stable, thanks. > > There are various causes for the inability to negotiate common SSL/TLS > protocol between client and server. Previously, we had a single, not > very actionable warning message for all of them. > > As people encountered TLS 1.0 servers in real life, it was quickly > obvious that the existing messaging was inadequate to help users > rectify the situation. > > This patch makes the warning messages much more verbose in hopes of > making them more actionable while simultaneously encouraging users > and servers to adopt better security practices. > > This messaging flirts with the anti-pattern of "never blame the > user" by signaling out poorly-configured servers. But if we're going to > disallow TLS 1.0 by default, I think we need to say *something* or > people are just going to blame Mercurial for not being able to connect. > The messaging tries to exonerate Mercurial from being the at fault > party by pointing out the server is the entity that doesn't support > proper security (when appropriate, of course). > > diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py > --- a/mercurial/sslutil.py > +++ b/mercurial/sslutil.py > @@ -412,21 +412,67 @@ def wrapsocket(sock, keyfile, certfile, > if (caloaded and settings['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')) > # Try to print more helpful error messages for known failures. > if util.safehasattr(e, '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 > + # TLS 1.1+ and the server only supports TLS 1.0. Whatever the > + # reason, try to emit an actionable warning. > if e.reason == 'UNSUPPORTED_PROTOCOL': > - ui.warn(_('(could not negotiate a common protocol; see ' > - 'https://mercurial-scm.org/wiki/SecureConnections ' > - 'for how to configure Mercurial to avoid this ' > - 'error)\n')) > + # We attempted TLS 1.0+. > + if settings['protocolui'] == '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 != set(['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') % ( > + serverhostname, > + ', '.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') % serverhostname) > + else: > + # We attempted TLS 1.1+. We can only get here if the client > + # supports the configured protocol. So the likely reason is > + # the client wants better security than the server can > + # 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') % ( > + settings['protocolui'], 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') % > + serverhostname) > + ui.warn(_( > + '(see https://mercurial-scm.org/wiki/SecureConnections ' > + 'for more info)\n')) > raise > > # check if wrap_socket failed silently because socket had been > # closed > # - see http://bugs.python.org/issue13721 > if not sslsocket.cipher(): > raise error.Abort(_('ssl connection failed')) > > diff --git a/tests/test-https.t b/tests/test-https.t > --- a/tests/test-https.t > +++ b/tests/test-https.t > @@ -464,30 +464,38 @@ Clients talking same TLS versions work > $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT1/ > 5fed3813f7f5 > $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT2/ > 5fed3813f7f5 > > Clients requiring newer TLS version than what server supports fail > > $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ > - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) > + (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) > + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) > + (see https://mercurial-scm.org/wiki/SecureConnections for more info) > abort: error: *unsupported protocol* (glob) > [255] > > $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT/ > - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) > + (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) > + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) > + (see https://mercurial-scm.org/wiki/SecureConnections for more info) > abort: error: *unsupported protocol* (glob) > [255] > $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT/ > - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) > + (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) > + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) > + (see https://mercurial-scm.org/wiki/SecureConnections for more info) > abort: error: *unsupported protocol* (glob) > [255] > $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT1/ > - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) > + (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) > + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) > + (see https://mercurial-scm.org/wiki/SecureConnections for more info) > abort: error: *unsupported protocol* (glob) > [255] > > --insecure will allow TLS 1.0 connections and override configs > > $ hg --config hostsecurity.minimumprotocol=tls1.2 id --insecure https://localhost:$HGPORT1/ > warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering > 5fed3813f7f5 > @@ -498,28 +506,32 @@ The per-host config option overrides the > > --config hostsecurity.minimumprotocol=tls1.2 \ > > --config hostsecurity.localhost:minimumprotocol=tls1.0 > 5fed3813f7f5 > > The per-host config option by itself works > > $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \ > > --config hostsecurity.localhost:minimumprotocol=tls1.2 > - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) > + (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) > + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) > + (see https://mercurial-scm.org/wiki/SecureConnections for more info) > abort: error: *unsupported protocol* (glob) > [255] > > .hg/hgrc file [hostsecurity] settings are applied to remote ui instances (issue5305) > > $ cat >> copy-pull/.hg/hgrc << EOF > > [hostsecurity] > > localhost:minimumprotocol=tls1.2 > > EOF > $ P="$CERTSDIR" hg -R copy-pull id https://localhost:$HGPORT/ > - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) > + (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) > + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) > + (see https://mercurial-scm.org/wiki/SecureConnections for more info) > abort: error: [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol (_ssl.c:590) > [255] > > $ killdaemons.py hg0.pid > $ killdaemons.py hg1.pid > $ killdaemons.py hg2.pid > #endif > > _______________________________________________ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Patch
diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py --- a/mercurial/sslutil.py +++ b/mercurial/sslutil.py @@ -412,21 +412,67 @@ def wrapsocket(sock, keyfile, certfile, if (caloaded and settings['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')) # Try to print more helpful error messages for known failures. if util.safehasattr(e, '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 + # TLS 1.1+ and the server only supports TLS 1.0. Whatever the + # reason, try to emit an actionable warning. if e.reason == 'UNSUPPORTED_PROTOCOL': - ui.warn(_('(could not negotiate a common protocol; see ' - 'https://mercurial-scm.org/wiki/SecureConnections ' - 'for how to configure Mercurial to avoid this ' - 'error)\n')) + # We attempted TLS 1.0+. + if settings['protocolui'] == '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 != set(['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') % ( + serverhostname, + ', '.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') % serverhostname) + else: + # We attempted TLS 1.1+. We can only get here if the client + # supports the configured protocol. So the likely reason is + # the client wants better security than the server can + # 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') % ( + settings['protocolui'], 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') % + serverhostname) + ui.warn(_( + '(see https://mercurial-scm.org/wiki/SecureConnections ' + 'for more info)\n')) raise # check if wrap_socket failed silently because socket had been # closed # - see http://bugs.python.org/issue13721 if not sslsocket.cipher(): raise error.Abort(_('ssl connection failed')) diff --git a/tests/test-https.t b/tests/test-https.t --- a/tests/test-https.t +++ b/tests/test-https.t @@ -464,30 +464,38 @@ Clients talking same TLS versions work $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT1/ 5fed3813f7f5 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT2/ 5fed3813f7f5 Clients requiring newer TLS version than what server supports fail $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) + (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) + (see https://mercurial-scm.org/wiki/SecureConnections for more info) abort: error: *unsupported protocol* (glob) [255] $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT/ - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) + (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) + (see https://mercurial-scm.org/wiki/SecureConnections for more info) abort: error: *unsupported protocol* (glob) [255] $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT/ - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) + (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) + (see https://mercurial-scm.org/wiki/SecureConnections for more info) abort: error: *unsupported protocol* (glob) [255] $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT1/ - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) + (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) + (see https://mercurial-scm.org/wiki/SecureConnections for more info) abort: error: *unsupported protocol* (glob) [255] --insecure will allow TLS 1.0 connections and override configs $ hg --config hostsecurity.minimumprotocol=tls1.2 id --insecure https://localhost:$HGPORT1/ warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering 5fed3813f7f5 @@ -498,28 +506,32 @@ The per-host config option overrides the > --config hostsecurity.minimumprotocol=tls1.2 \ > --config hostsecurity.localhost:minimumprotocol=tls1.0 5fed3813f7f5 The per-host config option by itself works $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \ > --config hostsecurity.localhost:minimumprotocol=tls1.2 - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) + (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) + (see https://mercurial-scm.org/wiki/SecureConnections for more info) abort: error: *unsupported protocol* (glob) [255] .hg/hgrc file [hostsecurity] settings are applied to remote ui instances (issue5305) $ cat >> copy-pull/.hg/hgrc << EOF > [hostsecurity] > localhost:minimumprotocol=tls1.2 > EOF $ P="$CERTSDIR" hg -R copy-pull id https://localhost:$HGPORT/ - (could not negotiate a common protocol; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error) + (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support) + (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server) + (see https://mercurial-scm.org/wiki/SecureConnections for more info) abort: error: [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol (_ssl.c:590) [255] $ killdaemons.py hg0.pid $ killdaemons.py hg1.pid $ killdaemons.py hg2.pid #endif