diff --git a/scapy/layers/tls/handshake.py b/scapy/layers/tls/handshake.py index 664729dd601..7a81acde443 100644 --- 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 index 09866823bb9..d0031e909cc 100644 --- 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) diff --git a/test/run_tests b/test/run_tests index cc2f57d215e..3d65a511cb5 100755 --- 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 index 8776910a3b0..d9414a34cbe 100644 --- 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\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\x13zh_ <\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 ############################## ###############################################################################