Patchwork [v3] sslutil-add tls 1.3 support - done during IETF101 Hackathon

login
register
mail settings
Submitter Codarren Velvindron
Date April 1, 2018, 4:55 a.m.
Message ID <20180401045527.GA6916@hackers.mu>
Download mbox | patch
Permalink /patch/30099/
State Superseded
Headers show

Comments

Codarren Velvindron - April 1, 2018, 4:55 a.m.
# HG changeset patch
# User Codarren Velvindron <codarren@hackers.mu>
# Date 1522557692 -14400
#      Sun Apr 01 08:41:32 2018 +0400
# Node ID 3a1cdeff1f61187e4a8af5f7259ca48039571b9e
# Parent  2ed180117f7658d0cbf6a1ece20944465c55c947
sslutil: add tls 1.3 support
Done during the IETF101 Hackathon.
Yuya Nishihara - April 1, 2018, 9:45 a.m.
On Sun, 1 Apr 2018 08:55:27 +0400, Codarren Velvindron wrote:
> # HG changeset patch
> # User Codarren Velvindron <codarren@hackers.mu>
> # Date 1522557692 -14400
> #      Sun Apr 01 08:41:32 2018 +0400
> # Node ID 3a1cdeff1f61187e4a8af5f7259ca48039571b9e
> # Parent  2ed180117f7658d0cbf6a1ece20944465c55c947
> sslutil: add tls 1.3 support

[...]

> -# TLS 1.1 and 1.2 may not be supported if the OpenSSL Python is compiled
> +# TLS 1.1, 1.2 and 1.3 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')
> +if util.safehasattr(ssl, 'PROTOCOL_TLSv1_3'):
> +    supportedprotocols.add('tls1.3')

While checking the test code, I noticed PROTOCOL_TLSv1_3 appears not provided
by the next Python 2. OP_NO_TLSv1_3 is claimed to be available in 2.7.15,
though.

https://docs.python.org/2.7/library/ssl.html

> +#if sslcontext tls1.3
> +Start servers running supported TLS versions
> +
> +  $ cd test
> +  $ hg serve -p $HGPORT3 -d --pid-file=../hg3.pid --certificate=$PRIV \
> +  > --config devel.serverexactprotocol=tls1.3
> +  $ cat ../hg3.pid >> $DAEMON_PIDS

$HGPORT3 isn't defined.

> +Clients talking same TLS versions work
> +
> +  $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.3 id https://localhost:$HGPORT3/
> +  5fed3813f7f5
> +
> +Clients requiring newer TLS version than what server supports fail
> +
> +  $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.3 id https://localhost:$HGPORT3/

Here we need to test the pair of TLS=1.3 client + TLS<1.3 server, but the server
supports TLS 1.3.
Codarren Velvindron - April 8, 2018, 3:41 a.m.
Hello Yuya,

On Sun, Apr 1, 2018 at 1:45 PM, Yuya Nishihara <yuya@tcha.org> wrote:

> On Sun, 1 Apr 2018 08:55:27 +0400, Codarren Velvindron wrote:
> > # HG changeset patch
> > # User Codarren Velvindron <codarren@hackers.mu>
> > # Date 1522557692 -14400
> > #      Sun Apr 01 08:41:32 2018 +0400
> > # Node ID 3a1cdeff1f61187e4a8af5f7259ca48039571b9e
> > # Parent  2ed180117f7658d0cbf6a1ece20944465c55c947
> > sslutil: add tls 1.3 support
>
> [...]

empty line will be removed

>
> > -# TLS 1.1 and 1.2 may not be supported if the OpenSSL Python is compiled
> > +# TLS 1.1, 1.2 and 1.3 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')
> > +if util.safehasattr(ssl, 'PROTOCOL_TLSv1_3'):
> > +    supportedprotocols.add('tls1.3')
>
> While checking the test code, I noticed PROTOCOL_TLSv1_3 appears not
> provided
> by the next Python 2. OP_NO_TLSv1_3 is claimed to be available in 2.7.15,
> though.
>
> https://docs.python.org/2.7/library/ssl.html

will use PROTOCOL_TLS instead.

>
> > +#if sslcontext tls1.3
> > +Start servers running supported TLS versions
> > +
> > +  $ cd test
> > +  $ hg serve -p $HGPORT3 -d --pid-file=../hg3.pid --certificate=$PRIV \
> > +  > --config devel.serverexactprotocol=tls1.3
> > +  $ cat ../hg3.pid >> $DAEMON_PIDS
>
> $HGPORT3 isn't defined.

can we reuse already defined variables? like $HGPORT? or should we define
new vars?

>
> > +Clients talking same TLS versions work
> > +
> > +  $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.3 id
> https://localhost:$HGPORT3/
> > +  5fed3813f7f5
> > +
> > +Clients requiring newer TLS version than what server supports fail
> > +
> > +  $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.3 id
> https://localhost:$HGPORT3/
>
> Here we need to test the pair of TLS=1.3 client + TLS<1.3 server, but the
> server
> supports TLS 1.3.
>
will correct this.

Thanks,
Codarren
Yuya Nishihara - April 8, 2018, 9:17 a.m.
On Sun, 8 Apr 2018 07:41:34 +0400, Codarren Velvindron wrote:
> > $HGPORT3 isn't defined.
> 
> can we reuse already defined variables? like $HGPORT? or should we define
> new vars?

After killing running daemons, yes.

Patch

diff -r 2ed180117f76 -r 3a1cdeff1f61 mercurial/help/config.txt
--- a/mercurial/help/config.txt	Sat Mar 31 13:01:20 2018 -0400
+++ b/mercurial/help/config.txt	Sun Apr 01 08:41:32 2018 +0400
@@ -1163,7 +1163,7 @@ 
     By default, the highest version of TLS supported by both client and server
     is used.
 
-    Allowed values are: ``tls1.0``, ``tls1.1``, ``tls1.2``.
+    Allowed values are: ``tls1.0``, ``tls1.1``, ``tls1.2``, ``tls1.3``.
 
     When running on an old Python version, only ``tls1.0`` is allowed since
     old versions of Python only support up to TLS 1.0.
diff -r 2ed180117f76 -r 3a1cdeff1f61 mercurial/sslutil.py
--- a/mercurial/sslutil.py	Sat Mar 31 13:01:20 2018 -0400
+++ b/mercurial/sslutil.py	Sun Apr 01 08:41:32 2018 +0400
@@ -38,17 +38,20 @@ 
     'tls1.0',
     'tls1.1',
     'tls1.2',
+    'tls1.3',
 }
 
 hassni = getattr(ssl, 'HAS_SNI', False)
 
-# TLS 1.1 and 1.2 may not be supported if the OpenSSL Python is compiled
+# TLS 1.1, 1.2 and 1.3 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')
+if util.safehasattr(ssl, 'PROTOCOL_TLSv1_3'):
+    supportedprotocols.add('tls1.3')
 
 try:
     # ssl.SSLContext was added in 2.7.9 and presence indicates modern
@@ -293,7 +296,7 @@ 
     # Despite its name, PROTOCOL_SSLv23 selects the highest protocol
     # that both ends support, including TLS protocols. On legacy stacks,
     # the highest it likely goes is TLS 1.0. On modern stacks, it can
-    # support TLS 1.2.
+    # support TLS 1.2 or 1.3.
     #
     # The PROTOCOL_TLSv* constants select a specific TLS version
     # only (as opposed to multiple versions). So the method for
@@ -323,6 +326,8 @@ 
         options |= ssl.OP_NO_TLSv1
     elif protocol == 'tls1.2':
         options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
+    elif protocol == 'tls1.3':
+        options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2
     else:
         raise error.Abort(_('this should not happen'))
 
@@ -542,6 +547,10 @@ 
         if 'tls1.2' not in supportedprotocols:
             raise error.Abort(_('TLS 1.2 not supported by this Python'))
         protocol = ssl.PROTOCOL_TLSv1_2
+    elif exactprotocol == 'tls1.3':
+        if 'tls1.3' not in supportedprotocols:
+            raise error.Abort(_('TLS 1.3 not supported by this Python'))
+        protocol = ssl.PROTOCOL_TLSv1_3
     elif exactprotocol:
         raise error.Abort(_('invalid value for serverexactprotocol: %s') %
                           exactprotocol)
diff -r 2ed180117f76 -r 3a1cdeff1f61 tests/hghave.py
--- a/tests/hghave.py	Sat Mar 31 13:01:20 2018 -0400
+++ b/tests/hghave.py	Sun Apr 01 08:41:32 2018 +0400
@@ -523,6 +523,11 @@ 
     from mercurial import sslutil
     return 'tls1.2' in sslutil.supportedprotocols
 
+@check("tls1.3", "TLS 1.3 protocol support")
+def has_tls1_3():
+    from mercurial import sslutil
+    return 'tls1.3' in sslutil.supportedprotocols
+
 @check("windows", "Windows")
 def has_windows():
     return os.name == 'nt'
diff -r 2ed180117f76 -r 3a1cdeff1f61 tests/test-https.t
--- a/tests/test-https.t	Sat Mar 31 13:01:20 2018 -0400
+++ b/tests/test-https.t	Sun Apr 01 08:41:32 2018 +0400
@@ -536,6 +536,55 @@ 
   $ killdaemons.py hg2.pid
 #endif
 
+#if sslcontext tls1.3
+Start servers running supported TLS versions
+
+  $ cd test
+  $ hg serve -p $HGPORT3 -d --pid-file=../hg3.pid --certificate=$PRIV \
+  > --config devel.serverexactprotocol=tls1.3
+  $ cat ../hg3.pid >> $DAEMON_PIDS
+  $ cd ..
+
+Clients talking same TLS versions work
+
+  $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.3 id https://localhost:$HGPORT3/
+  5fed3813f7f5
+
+Clients requiring newer TLS version than what server supports fail
+
+  $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.3 id https://localhost:$HGPORT3/
+  (could not negotiate a common security protocol (tls1.3+) 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.3 id --insecure https://localhost:$HGPORT3/
+  warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
+  5fed3813f7f5
+
+The per-host config option overrides the default
+
+  $ P="$CERTSDIR" hg id https://localhost:$HGPORT3/ \
+  > --config hostsecurity.minimumprotocol=tls1.3 \
+  > --config hostsecurity.localhost:minimumprotocol=tls1.0
+  5fed3813f7f5
+
+The per-host config option by itself works
+
+  $ P="$CERTSDIR" hg id https://localhost:$HGPORT3/ \
+  > --config hostsecurity.localhost:minimumprotocol=tls1.3
+  (could not negotiate a common security protocol (tls1.3+) 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]
+
+  $ killdaemons.py hg3.pid
+#endif
+
 Prepare for connecting through proxy
 
   $ hg serve -R test -p $HGPORT -d --pid-file=hg0.pid --certificate=$PRIV