Repository: secdev/scapy

Issue:
Broken TLS session while server choose TLSv1.2 instead of TLSv1.3
<!--
Things to consider

1.  Please check that you are using the latest scapy version, e.g. installed via:

    `pip install --upgrade git+git://github.com/secdev/scapy`

2.  If you are here to ask a question - please check previous issues and online resources, and consider using gitter instead: <https://gitter.im/secdev/scapy>

3.  Please understand that **this is not a forum** but an issue tracker. The following article explains why you should limit questions asked on Github issues: <https://medium.com/@methane/why-you-must-not-ask-questions-on-github-issues-51d741d83fde>
-->

#### Brief description

<!-- describe the main issue in one sentence -->
<!-- if possible, describe what components / protocols could be affected by the issue (e.g. wrpcap() + IPv6, it is likely this also affects XXX) -->
Broken TLS session while parsing dump from server with disabled TLSv1.3.

Client supports both TLS 1.2 and 1.3:
```
   |   |###[ TLS Extension - Supported Versions (for ClientHello) ]###
   |   |  type      = supported_versions
   |   |  len       = 5
   |   |  versionslen= 4
   |   |  versions  = [TLS 1.3, TLS 1.2]
```
But server works only with TLS 1.2:
```
   |###[ TLS Handshake - Server Hello ]###
   |  msgtype   = server_hello
   |  msglen    = 81
   |  version   = TLS 1.2
```
Looks like TLSSession saves TLSv1.3 from `ClientHello` and do not downgraded with `ServerHello`.

If restrict client to TLSv1.2 (curl `--tls-max 1.2` option) it start works as expected.

#### Environment

-   Scapy version: `2.4.4rc2.dev30`
-   Python version: `3.7.5`
-   Operating System: `Ubuntu 18.04.3 LTS`

<!-- if needed - further information to get a picture of your setup (e.g. a sketch of your network setup) -->

#### How to reproduce
[scapy_client_tls13_server_tls12.pcap](https://drive.google.com/file/d/1yy0BRSwQKVLSlqnYv9hY0W0GbgoYFCED/view)
```python3
from scapy.all import *
load_layer('tls')
pcap = rdpcap('scapy_client_tls13_server_tls12.pcap')
r1 = TLS(pcap[0].load)
r2 = TLS(pcap[1].load, tls_session=r1.tls_session.mirror())
```
<!-- step-by-step explanation or a short script, may reference section 'Related resources' -->

#### Actual result

```python3
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-4c9f13dcdcd8> in <module>
----> 1 r2 = TLS(pcap[1].load, tls_session=r1.tls_session.mirror())

~/scapy_venv/lib/python3.7/site-packages/scapy/base_classes.py in __call__(cls, *args, **kargs)
    264                 cls = config.conf.raw_layer
    265         i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__)
--> 266         i.__init__(*args, **kargs)
    267         return i
    268

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/record.py in __init__(self, *args, **kargs)
    302     def __init__(self, *args, **kargs):
    303         self.deciphered_len = kargs.get("deciphered_len", None)
--> 304         super(TLS, self).__init__(*args, **kargs)
    305
    306     @classmethod

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/session.py in __init__(self, _pkt, post_transform, _internal, _underlayer, tls_session, **fields)
    902         Packet.__init__(self, _pkt=_pkt, post_transform=post_transform,
    903                         _internal=_internal, _underlayer=_underlayer,
--> 904                         **fields)
    905
    906     def __getattr__(self, attr):

~/scapy_venv/lib/python3.7/site-packages/scapy/packet.py in __init__(self, _pkt, post_transform, _internal, _underlayer, **fields)
    156         self.sniffed_on = None
    157         if _pkt:
--> 158             self.dissect(_pkt)
    159             if not _internal:
    160                 self.dissection_done(self)

~/scapy_venv/lib/python3.7/site-packages/scapy/packet.py in dissect(self, s)
    873         s = self.pre_dissect(s)
    874
--> 875         s = self.do_dissect(s)
    876
    877         s = self.post_dissect(s)

~/scapy_venv/lib/python3.7/site-packages/scapy/packet.py in do_dissect(self, s)
    837             if not s:
    838                 break
--> 839             s, fval = f.getfield(self, s)
    840             # We need to track fields with mutable values to discard
    841             # .raw_packet_cache when needed.

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/record.py in getfield(self, pkt, s)
    166                 if isinstance(p, _GenericTLSSessionInheritance):
    167                     if not p.tls_session.frozen:
--> 168                         p.post_dissection_tls_session_update(raw_msg)
    169
    170                 lst.append(p)

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/session.py in post_dissection_tls_session_update(self, msg_str)
    924
    925     def post_dissection_tls_session_update(self, msg_str):
--> 926         self.tls_session_update(msg_str)
    927
    928     def copy(self):

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/handshake.py in tls_session_update(self, msg_str)
    648             s.prcs = readConnState(ciphersuite=cs_cls,
    649                                    connection_end=connection_end,
--> 650                                    tls_version=s.tls_version)
    651             if not s.middlebox_compatibility:
    652                 s.triggered_prcs_commit = True

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/session.py in __init__(self, **kargs)
    279 class readConnState(connState):
    280     def __init__(self, **kargs):
--> 281         connState.__init__(self, read_or_write="read", **kargs)
    282
    283

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/session.py in __init__(self, connection_end, read_or_write, seq_num, compression_alg, ciphersuite, tls_version)
     89             from scapy.layers.tls.crypto.suites import TLS_NULL_WITH_NULL_NULL
     90             ciphersuite = TLS_NULL_WITH_NULL_NULL
---> 91         self.ciphersuite = ciphersuite(tls_version=tls_version)
     92
     93         if not self.ciphersuite.usable:

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/crypto/suites.py in __init__(self, tls_version)
    140         """
    141         super(_GenericCipherSuite, self).__init__()
--> 142         if tls_version <= 0x301:
    143             self.key_block_len = self._key_block_len_v1_0
    144

TypeError: '<=' not supported between instances of 'NoneType' and 'int'
```
<!-- dump results that outline the issue, please format your code -->

#### Expected result

Correct work of TLSSession (saves TLSv1.2 as `tls_version` on parsing `ServerHello`) in that case.

<!-- describe the expected result and outline the difference to the actual one, could also be a screen shot (e.g. wireshark) -->

#### Related resources

<!-- traces / sample pcaps (stripped to the relevant frames), related standards, RFCs or other resources -->

Broken TLS session while server choose TLSv1.2 instead of TLSv1.3
<!--
Things to consider

1.  Please check that you are using the latest scapy version, e.g. installed via:

    `pip install --upgrade git+git://github.com/secdev/scapy`

2.  If you are here to ask a question - please check previous issues and online resources, and consider using gitter instead: <https://gitter.im/secdev/scapy>

3.  Please understand that **this is not a forum** but an issue tracker. The following article explains why you should limit questions asked on Github issues: <https://medium.com/@methane/why-you-must-not-ask-questions-on-github-issues-51d741d83fde>
-->

#### Brief description

<!-- describe the main issue in one sentence -->
<!-- if possible, describe what components / protocols could be affected by the issue (e.g. wrpcap() + IPv6, it is likely this also affects XXX) -->
Broken TLS session while parsing dump from server with disabled TLSv1.3.

Client supports both TLS 1.2 and 1.3:
```
   |   |###[ TLS Extension - Supported Versions (for ClientHello) ]###
   |   |  type      = supported_versions
   |   |  len       = 5
   |   |  versionslen= 4
   |   |  versions  = [TLS 1.3, TLS 1.2]
```
But server works only with TLS 1.2:
```
   |###[ TLS Handshake - Server Hello ]###
   |  msgtype   = server_hello
   |  msglen    = 81
   |  version   = TLS 1.2
```
Looks like TLSSession saves TLSv1.3 from `ClientHello` and do not downgraded with `ServerHello`.

If restrict client to TLSv1.2 (curl `--tls-max 1.2` option) it start works as expected.

#### Environment

-   Scapy version: `2.4.4rc2.dev30`
-   Python version: `3.7.5`
-   Operating System: `Ubuntu 18.04.3 LTS`

<!-- if needed - further information to get a picture of your setup (e.g. a sketch of your network setup) -->

#### How to reproduce
[scapy_client_tls13_server_tls12.pcap](https://drive.google.com/file/d/1yy0BRSwQKVLSlqnYv9hY0W0GbgoYFCED/view)
```python3
from scapy.all import *
load_layer('tls')
pcap = rdpcap('scapy_client_tls13_server_tls12.pcap')
r1 = TLS(pcap[0].load)
r2 = TLS(pcap[1].load, tls_session=r1.tls_session.mirror())
```
<!-- step-by-step explanation or a short script, may reference section 'Related resources' -->

#### Actual result

```python3
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-4c9f13dcdcd8> in <module>
----> 1 r2 = TLS(pcap[1].load, tls_session=r1.tls_session.mirror())

~/scapy_venv/lib/python3.7/site-packages/scapy/base_classes.py in __call__(cls, *args, **kargs)
    264                 cls = config.conf.raw_layer
    265         i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__)
--> 266         i.__init__(*args, **kargs)
    267         return i
    268

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/record.py in __init__(self, *args, **kargs)
    302     def __init__(self, *args, **kargs):
    303         self.deciphered_len = kargs.get("deciphered_len", None)
--> 304         super(TLS, self).__init__(*args, **kargs)
    305
    306     @classmethod

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/session.py in __init__(self, _pkt, post_transform, _internal, _underlayer, tls_session, **fields)
    902         Packet.__init__(self, _pkt=_pkt, post_transform=post_transform,
    903                         _internal=_internal, _underlayer=_underlayer,
--> 904                         **fields)
    905
    906     def __getattr__(self, attr):

~/scapy_venv/lib/python3.7/site-packages/scapy/packet.py in __init__(self, _pkt, post_transform, _internal, _underlayer, **fields)
    156         self.sniffed_on = None
    157         if _pkt:
--> 158             self.dissect(_pkt)
    159             if not _internal:
    160                 self.dissection_done(self)

~/scapy_venv/lib/python3.7/site-packages/scapy/packet.py in dissect(self, s)
    873         s = self.pre_dissect(s)
    874
--> 875         s = self.do_dissect(s)
    876
    877         s = self.post_dissect(s)

~/scapy_venv/lib/python3.7/site-packages/scapy/packet.py in do_dissect(self, s)
    837             if not s:
    838                 break
--> 839             s, fval = f.getfield(self, s)
    840             # We need to track fields with mutable values to discard
    841             # .raw_packet_cache when needed.

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/record.py in getfield(self, pkt, s)
    166                 if isinstance(p, _GenericTLSSessionInheritance):
    167                     if not p.tls_session.frozen:
--> 168                         p.post_dissection_tls_session_update(raw_msg)
    169
    170                 lst.append(p)

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/session.py in post_dissection_tls_session_update(self, msg_str)
    924
    925     def post_dissection_tls_session_update(self, msg_str):
--> 926         self.tls_session_update(msg_str)
    927
    928     def copy(self):

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/handshake.py in tls_session_update(self, msg_str)
    648             s.prcs = readConnState(ciphersuite=cs_cls,
    649                                    connection_end=connection_end,
--> 650                                    tls_version=s.tls_version)
    651             if not s.middlebox_compatibility:
    652                 s.triggered_prcs_commit = True

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/session.py in __init__(self, **kargs)
    279 class readConnState(connState):
    280     def __init__(self, **kargs):
--> 281         connState.__init__(self, read_or_write="read", **kargs)
    282
    283

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/session.py in __init__(self, connection_end, read_or_write, seq_num, compression_alg, ciphersuite, tls_version)
     89             from scapy.layers.tls.crypto.suites import TLS_NULL_WITH_NULL_NULL
     90             ciphersuite = TLS_NULL_WITH_NULL_NULL
---> 91         self.ciphersuite = ciphersuite(tls_version=tls_version)
     92
     93         if not self.ciphersuite.usable:

~/scapy_venv/lib/python3.7/site-packages/scapy/layers/tls/crypto/suites.py in __init__(self, tls_version)
    140         """
    141         super(_GenericCipherSuite, self).__init__()
--> 142         if tls_version <= 0x301:
    143             self.key_block_len = self._key_block_len_v1_0
    144

TypeError: '<=' not supported between instances of 'NoneType' and 'int'
```
<!-- dump results that outline the issue, please format your code -->

#### Expected result

Correct work of TLSSession (saves TLSv1.2 as `tls_version` on parsing `ServerHello`) in that case.

<!-- describe the expected result and outline the difference to the actual one, could also be a screen shot (e.g. wireshark) -->

#### Related resources

<!-- traces / sample pcaps (stripped to the relevant frames), related standards, RFCs or other resources -->



Discussion:
Setting `tls_session.advertised_tls_version = None` before dissect `ServerHello` packet fixed this case.  
But it possible broke `TLS13ServerHello`.  

Looks like need common `TLSServerHello` class which detect TLS version by itself.
Setting `tls_session.advertised_tls_version = None` before dissect `ServerHello` packet fixed this case.  
But it possible broke `TLS13ServerHello`.  

Looks like need common `TLSServerHello` class which detect TLS version by itself.

Resolving patch:
diff --git a/scapy/layers/tls/handshake.py b/scapy/layers/tls/handshake.py
--- a/scapy/layers/tls/handshake.py
+++ b/scapy/layers/tls/handshake.py
@@ -324,7 +324,7 @@ def tls_session_update(self, msg_str):
         if self.ext:
             for e in self.ext:
                 if isinstance(e, TLS_Ext_SupportedVersion_CH):
-                    for ver in e.versions:
+                    for ver in sorted(e.versions, reverse=True):
                         # RFC 8701: GREASE of TLS will send unknown versions
                         # here. We have to ignore them
                         if ver in _tls_version:
@@ -455,7 +455,7 @@ def tls_session_update(self, msg_str):
         if self.ext:
             for e in self.ext:
                 if isinstance(e, TLS_Ext_SupportedVersion_CH):
-                    for ver in e.versions:
+                    for ver in sorted(e.versions, reverse=True):
                         # RFC 8701: GREASE of TLS will send unknown versions
                         # here. We have to ignore them
                         if ver in _tls_version:
@@ -530,12 +530,15 @@ def tls_session_update(self, msg_str):
         """
         super(TLSServerHello, self).tls_session_update(msg_str)
 
-        self.tls_session.tls_version = self.version
-        self.random_bytes = msg_str[10:38]
-        self.tls_session.server_random = (struct.pack('!I',
-                                                      self.gmt_unix_time) +
-                                          self.random_bytes)
-        self.tls_session.sid = self.sid
+        s = self.tls_session
+        s.tls_version = self.version
+        if hasattr(self, 'gmt_unix_time'):
+            self.random_bytes = msg_str[10:38]
+            s.server_random = (struct.pack('!I', self.gmt_unix_time) +
+                               self.random_bytes)
+        else:
+            s.server_random = self.random_bytes
+        s.sid = self.sid
 
         cs_cls = None
         if self.cipher:
@@ -555,15 +558,15 @@ def tls_session_update(self, msg_str):
                 comp_val = 0
             comp_cls = _tls_compression_algs_cls[comp_val]
 
-        connection_end = self.tls_session.connection_end
-        self.tls_session.pwcs = writeConnState(ciphersuite=cs_cls,
-                                               compression_alg=comp_cls,
-                                               connection_end=connection_end,
-                                               tls_version=self.version)
-        self.tls_session.prcs = readConnState(ciphersuite=cs_cls,
-                                              compression_alg=comp_cls,
-                                              connection_end=connection_end,
-                                              tls_version=self.version)
+        connection_end = s.connection_end
+        s.pwcs = writeConnState(ciphersuite=cs_cls,
+                                compression_alg=comp_cls,
+                                connection_end=connection_end,
+                                tls_version=self.version)
+        s.prcs = readConnState(ciphersuite=cs_cls,
+                               compression_alg=comp_cls,
+                               connection_end=connection_end,
+                               tls_version=self.version)
 
 
 _tls_13_server_hello_fields = [
@@ -586,7 +589,7 @@ def tls_session_update(self, msg_str):
 ]
 
 
-class TLS13ServerHello(_TLSHandshake):
+class TLS13ServerHello(TLSServerHello):
     """ TLS 1.3 ServerHello """
     name = "TLS 1.3 Handshake - Server Hello"
     fields_desc = _tls_13_server_hello_fields
@@ -615,16 +618,23 @@ def tls_session_update(self, msg_str):
         cipher suite (if recognized), and finally we instantiate the write and
         read connection states.
         """
-        super(TLS13ServerHello, self).tls_session_update(msg_str)
-
         s = self.tls_session
+        s.server_random = self.random_bytes
+        s.ciphersuite = self.cipher
+        s.tls_version = self.version
+        # Check extensions
         if self.ext:
             for e in self.ext:
                 if isinstance(e, TLS_Ext_SupportedVersion_SH):
                     s.tls_version = e.version
                     break
-        s.server_random = self.random_bytes
-        s.ciphersuite = self.cipher
+
+        if s.tls_version < 0x304:
+            # This means that the server does not support TLS 1.3 and ignored
+            # the initial TLS 1.3 ClientHello. tls_version has been updated
+            return TLSServerHello.tls_session_update(self, msg_str)
+        else:
+            _TLSHandshake.tls_session_update(self, msg_str)
 
         cs_cls = None
         if self.cipher:
diff --git a/scapy/layers/tls/record.py b/scapy/layers/tls/record.py
--- a/scapy/layers/tls/record.py
+++ b/scapy/layers/tls/record.py
@@ -93,9 +93,16 @@ def m2i(self, pkt, m):
         if pkt.type == 22:
             if len(m) >= 1:
                 msgtype = orb(m[0])
-                if ((pkt.tls_session.advertised_tls_version == 0x0304) or
-                        (pkt.tls_session.tls_version and
-                         pkt.tls_session.tls_version == 0x0304)):
+                # If a version was agreed on by both client and server,
+                # we use it (tls_session.tls_version)
+                # Otherwise, if the client advertised for TLS 1.3, we try to
+                # dissect the following packets (most likely, server hello)
+                # using TLS 1.3. The serverhello is able to fallback on
+                # TLS 1.2 if necessary. In any case, this will set the agreed
+                # version so that all future packets are correct.
+                if ((pkt.tls_session.advertised_tls_version == 0x0304 and
+                        pkt.tls_session.tls_version is None) or
+                        pkt.tls_session.tls_version == 0x0304):
                     cls = _tls13_handshake_cls.get(msgtype, Raw)
                 else:
                     cls = _tls_handshake_cls.get(msgtype, Raw)


Test patch:
diff --git a/test/run_tests b/test/run_tests
--- a/test/run_tests
+++ b/test/run_tests
@@ -2,16 +2,17 @@
 DIR=$(dirname "$0")/..
 if [ -z "$PYTHON" ]
 then
-  ARGS=$(getopt 23 "$*" 2> /dev/null)
-  for arg in $ARGS
+  ARGS=""
+  for arg in "$@"
   do
     case $arg
     in
-      -2) PYTHON=python2; shift;;
-      -3) PYTHON=python3; shift;;
-      --) PYTHON=python3; break;;
+      -2) PYTHON=python2;;
+      -3) PYTHON=python3;;
+       *) ARGS="$ARGS $arg";;
     esac
   done
+  PYTHON=${PYTHON:-python3}
 fi
 $PYTHON --version > /dev/null 2>&1
 if [ ! $? -eq 0 ]
diff --git a/test/tls.uts b/test/tls.uts
--- a/test/tls.uts
+++ b/test/tls.uts
@@ -1019,6 +1019,7 @@ conf.debug_dissector = old_debug_dissector
 = Test x25519 dissection in ServerKeyExchange
 
 import binascii
+from scapy.layers.tls.session import tlsSession
 
 session = tlsSession(connection_end="client")
 # Raw hex data of a TLS Handshake - Server Key Exchange with x25519 elliptic curve
@@ -1413,6 +1414,12 @@ assert p.msg[0].extlen is None
 assert p.msg[0].ext == []
 assert [type(x) for x in a.msg] == [TLSServerHello, TLSCertificate, TLSServerKeyExchange, TLSServerHelloDone]
 
+= Issue 2778
+
+r1 = TLS(b"\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03\xf8\xb3\xdb\xcbp\xed8\x04\x00\x9c\x15\xafJB\x98r\x06\x19\xb7\r\x1a\xd4\xf2M\x0e\x99\xde\x9e\x93\xce<; \x1c;,\xf3&k\xcb\xa1\x9b)G\x9e\xc6o\xe8\x15\xf7\xdb\nk\x97a\x11\xf7\tX9^z\xee\xba\xba\x00>\x13\x02\x13\x03\x13\x01\xc0,\xc00\x00\x9f\xcc\xa9\xcc\xa8\xcc\xaa\xc0+\xc0/\x00\x9e\xc0$\xc0(\x00k\xc0#\xc0'\x00g\xc0\n\xc0\x14\x009\xc0\t\xc0\x13\x003\x00\x9d\x00\x9c\x00=\x00<\x005\x00/\x00\xff\x01\x00\x01u\x00\x0b\x00\x04\x03\x00\x01\x02\x00\n\x00\x0c\x00\n\x00\x1d\x00\x17\x00\x1e\x00\x19\x00\x183t\x00\x00\x00\x10\x00\x0e\x00\x0c\x02h2\x08http/1.1\x00\x16\x00\x00\x00\x17\x00\x00\x001\x00\x00\x00\r\x00*\x00(\x04\x03\x05\x03\x06\x03\x08\x07\x08\x08\x08\t\x08\n\x08\x0b\x08\x04\x08\x05\x08\x06\x04\x01\x05\x01\x06\x01\x03\x03\x03\x01\x03\x02\x04\x02\x05\x02\x06\x02\x00+\x00\x05\x04\x03\x04\x03\x03\x00-\x00\x02\x01\x01\x003\x00&\x00$\x00\x1d\x00 \xe8A\x0fZ\xb0\x9d\x96\xb0_\x10\x18<\xcd\x9e\x93\xa0W\xa72\x90\xb4\xc9\xe1\xc2T\xcd\xfc)\x9f\xc0\x1dA\x00\x15\x00\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
+r2 = TLS(b'\x16\x03\x03\x00U\x02\x00\x00Q\x03\x03 \xa5@2G~\xa3\xa9c\xb8\xa7\x00\t\x04Y\xf1\x1f\x1fJ\xd1\x89n\x1dut[~+\xdcQ\xdd\xe0 \x06\x00\xf5R\xdblQ\xb9z0\x97\x17\xff\x84{\xb6\xe8\xfe\xf1\xce&\x01TD\x13\xfd\xa7\xb6`u\xb8\x87\x00\x9d\x00\x00\t\xff\x01\x00\x01\x00\x00\x17\x00\x00\x16\x03\x03\x03n\x0b\x00\x03j\x00\x03g\x00\x03d0\x82\x03`0\x82\x02H\xa0\x03\x02\x01\x02\x02\t\x00\xebs\xb7\x1c>/\x9f\xdc0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x000E1\x0b0\t\x06\x03U\x04\x06\x13\x02AU1\x130\x11\x06\x03U\x04\x08\x0c\nSome-State1!0\x1f\x06\x03U\x04\n\x0c\x18Internet Widgits Pty Ltd0\x1e\x17\r190215151403Z\x17\r290212151403Z0E1\x0b0\t\x06\x03U\x04\x06\x13\x02AU1\x130\x11\x06\x03U\x04\x08\x0c\nSome-State1!0\x1f\x06\x03U\x04\n\x0c\x18Internet Widgits Pty Ltd0\x82\x01"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xd2\xf7\xd3k#:V\x196\x8f\xc3\xa7\xdb\x0f#d\xdcq\x98m\xd4\xee\xbc\xbe\xe8[x>\x13\x9c\xfe\xb0\xa8\r\xe5\x01G\xc96\xaa\x84#\x0e/\xa2\xeb\x91\xef\x177A\x03\x87\xb92D\n\xc7\xcf\xda<Yf\xee\xf8\x8fh\x8b\xcb\xeej]\r\xfa\xa0u\xb7}\xfe\x83o,\xb3\x187_\xf5\xbe+5\xf6\xd6-\xd7\xc4\xb1G"Og\xd5=\x95\xc7\xfc\xc1\x1c\xda{\xc6"6\x9bMJhVU\x16\x9f\xb2\x8ff\xe5\x11rO\x0c\x9a\xf2\xf7N\xa4\xcd\xf0\x9b\x92\xf9\x17$jX/g\xfa\xde>\xff~\xca,yMq<\x13\xf8\x0c\xd5?\x84z\xa1\x96\xd0\xad\xc0D\x94y\nb\x8e2\x7fKS\xd0[\x83\x02\\>\xa5A\x19_\x95<\xe6\xfc7\xed\xcch\xa8\xfdn\xcab\x1f8\xbc\x08\xbc-\x8dr\xcf\xcd\xf8\\h\xf9\xf4\xf4H[2\x13<c)\x9f\x85\xff\xd6+\xdeZ\x9dX^Z\x89o\x081\x94H\'\x7f\x19\xe8m]hx\xbcSv\x8b.\xf9\xb3!\x02\x03\x01\x00\x01\xa3S0Q0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14\x82\x97\xfb\x8c\xf3\xd9\xdd\xf2\xf6\x0e\xc9\x0f\x92\x81\\(\xe3\xf3\xff50\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14\x82\x97\xfb\x8c\xf3\xd9\xdd\xf2\xf6\x0e\xc9\x0f\x92\x81\\(\xe3\xf3\xff50\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00<\x00\x1f\x0f]\x10`r\xe0\xbe\xed\xfaG\x89S)\xd4b4"\x08\x0ef\xca\xa4\xbe\xb4\xc3\xd9\xb6\x86\x8f\xa1\x07F}a`\xe5\x12\xed\xe7\xcb\xbe\xfd\xeb\x17\xc0\x9b\x9fYO\x86\xf1\xa9\x92,\x98,\xcf\x96U\xd4\xd6~\xda\x06\x1ff~\xeb%\xfer\x03\xbe\xa0\x0e@\xf1P\xa4\x90\xa7\x8c\xa9c\xd8|\x18Z\xde\x8b|)OPR\xfb\x1e\x1e\xdb4\x03\x83\x1e3\xe4\x02l\x8eVq|\xb7{\xc3#!\x85\x8b\xe3zw\xfe\x7fU\x11\xef\x8c \x13\xc8n\'0\xc5\xb26hu\x13\x1c\xae\x0cv\x16\xfd\xc7\xc8`V\x96\x13>zh_  <\r\xb8\xe0\xff\x1d\x1aY\x91\xd2\xf0X\xf4\x8f \xb1\n_\xb0\xdf\'\xa1\xf9\x87L\xc0\xfe\x8dn\xbfw\xe9\xa7\xba8I\x0e\x9dc$\x1a\x0f\xb3\xfdw\x01\xff;\x13\x0c\x9a\xa7\xaaww\x02\x80\xb7\x00<\x1b\xb5\xe0xL4\xaa\xcbt\xce\x81\x14\x96\x0eP\xee\xe0F\x02\xa7\xab \xe5\xc8x\x02\x8eB\x92\xe9\x0e@\xfdc\x1f\xee\x16\x03\x03\x00\x04\x0e\x00\x00\x00', tls_session=r1.tls_session.mirror())
+assert r2.tls_session.tls_version == 0x303
+
 ###############################################################################
 ############################ Automaton behaviour ##############################
 ###############################################################################