Skip to content

Commit cffd083

Browse files
committed
TLS sessions: multiple improvements and cleanups
1 parent 2f8ffe0 commit cffd083

File tree

8 files changed

+82
-28
lines changed

8 files changed

+82
-28
lines changed

doc/scapy/usage.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,6 @@ Those sessions can be used using the ``session=`` parameter of ``sniff()``. Exam
802802
To implement your own Session class, in order to support another flow-based protocol, start by copying a sample from `scapy/sessions.py <https://github.com/secdev/scapy/blob/master/scapy/sessions.py>`_
803803
Your custom ``Session`` class only needs to extend the :py:class:`~scapy.sessions.DefaultSession` class, and implement a ``on_packet_received`` function, such as in the example.
804804

805-
.. note:: Would you need it, you can use: ``class TLS_over_TCP(TLSSession, TCPSession): pass`` to sniff TLS packets that are defragmented.
806805

807806
How to use TCPSession to defragment TCP packets
808807
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

scapy/layers/tls/record.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,6 @@
4040
if conf.crypto_valid_advanced:
4141
from scapy.layers.tls.crypto.cipher_aead import Cipher_CHACHA20_POLY1305
4242

43-
# Util
44-
45-
46-
def _tls_version_check(version, min):
47-
"""Returns if version >= min, or False if version == None"""
48-
if version is None:
49-
return False
50-
return version >= min
5143

5244
###############################################################################
5345
# TLS Record Protocol #
@@ -216,7 +208,7 @@ def addfield(self, pkt, s, val):
216208
# Add TLS13ClientHello in case of HelloRetryRequest
217209
# Add ChangeCipherSpec for middlebox compatibility
218210
if (isinstance(pkt, _GenericTLSSessionInheritance) and
219-
_tls_version_check(pkt.tls_session.tls_version, 0x0304) and
211+
pkt.tls_session.tls_version == 0x0304 and
220212
not isinstance(pkt.msg[0], TLS13ServerHello) and
221213
not isinstance(pkt.msg[0], TLS13ClientHello) and
222214
not isinstance(pkt.msg[0], TLSChangeCipherSpec)):
@@ -337,7 +329,7 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs):
337329
# Not SSLv2: continuation
338330
return _TLSEncryptedContent
339331
# Check TLS 1.3
340-
if s and _tls_version_check(s.tls_version, 0x0304):
332+
if s and s.tls_version == 0x0304:
341333
_has_cipher = lambda x: (
342334
x and not isinstance(x.cipher, Cipher_NULL)
343335
)
@@ -734,11 +726,11 @@ def post_build(self, pkt, pay):
734726
return hdr + efrag + pay
735727

736728
def mysummary(self):
737-
s = super(TLS, self).mysummary()
729+
s, n = super(TLS, self).mysummary()
738730
if self.msg:
739731
s += " / "
740732
s += " / ".join(getattr(x, "_name", x.name) for x in self.msg)
741-
return s
733+
return s, n
742734

743735
###############################################################################
744736
# TLS ChangeCipherSpec #

scapy/layers/tls/record_tls13.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,10 @@ def post_build(self, pkt, pay):
223223
self.tls_session.triggered_pwcs_commit = False
224224

225225
return hdr + frag + pay
226+
227+
def mysummary(self):
228+
s, n = super(TLS13, self).mysummary()
229+
if self.inner and self.inner.msg:
230+
s += " / "
231+
s += " / ".join(getattr(x, "_name", x.name) for x in self.inner.msg)
232+
return s, n

scapy/layers/tls/session.py

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from scapy.error import log_runtime, warning
1919
from scapy.packet import Packet
2020
from scapy.pton_ntop import inet_pton
21-
from scapy.sessions import DefaultSession
21+
from scapy.sessions import TCPSession
2222
from scapy.utils import repr_hex, strxor
2323
from scapy.layers.inet import TCP
2424
from scapy.layers.tls.crypto.compression import Comp_NULL
@@ -903,13 +903,20 @@ def eq(self, other):
903903

904904
return False
905905

906-
def __repr__(self):
906+
def repr(self, _underlayer=None):
907907
sid = repr(self.sid)
908908
if len(sid) > 12:
909909
sid = sid[:11] + "..."
910+
if _underlayer and _underlayer.dport != self.dport:
911+
return "%s:%s > %s:%s" % (self.ipdst, str(self.dport),
912+
self.ipsrc, str(self.sport))
910913
return "%s:%s > %s:%s" % (self.ipsrc, str(self.sport),
911914
self.ipdst, str(self.dport))
912915

916+
def __repr__(self):
917+
return self.repr()
918+
919+
913920
###############################################################################
914921
# Session singleton #
915922
###############################################################################
@@ -1079,25 +1086,41 @@ def show2(self):
10791086
s.rcs = rcs_snap
10801087
s.wcs = wcs_snap
10811088

1082-
def mysummary(self):
1083-
return "TLS %s / %s" % (repr(self.tls_session),
1084-
getattr(self, "_name", self.name))
1089+
def mysummary(self, first=True):
1090+
from scapy.layers.tls.record import TLS
1091+
from scapy.layers.tls.record_tls13 import TLS13
1092+
if (
1093+
self.underlayer and
1094+
isinstance(self.underlayer, _GenericTLSSessionInheritance)
1095+
):
1096+
summary = getattr(self, "_name", self.name)
1097+
else:
1098+
_underlayer = None
1099+
if self.underlayer and isinstance(self.underlayer, TCP):
1100+
_underlayer = self.underlayer
1101+
summary = "TLS %s / %s" % (
1102+
self.tls_session.repr(_underlayer=_underlayer),
1103+
getattr(self, "_name", self.name)
1104+
)
1105+
return summary, [TLS, TLS13]
10851106

10861107
@classmethod
10871108
def tcp_reassemble(cls, data, metadata, session):
1088-
# Used with TLSSession
1109+
# Used with TCPSession
10891110
from scapy.layers.tls.record import TLS
10901111
from scapy.layers.tls.record_tls13 import TLS13
10911112
if cls in (TLS, TLS13):
1092-
length = struct.unpack("!H", data[3:5])[0] + 5
1113+
length = 0
1114+
curdata = data
1115+
while len(curdata) > 5:
1116+
clength = struct.unpack("!H", curdata[3:5])[0] + 5
1117+
curdata = curdata[clength:]
1118+
length += clength
10931119
if len(data) == length:
1094-
return cls(data)
1095-
elif len(data) > length:
1096-
pkt = cls(data)
1097-
if hasattr(pkt.payload, "tcp_reassemble"):
1098-
return pkt.payload.tcp_reassemble(data[length:], metadata, session)
1099-
else:
1100-
return pkt
1120+
# get the underlayer as it is used to populate tls_session
1121+
underlayer = metadata["original"][TCP].copy()
1122+
underlayer.remove_payload()
1123+
return cls(data, _underlayer=underlayer)
11011124
else:
11021125
return cls(data)
11031126

@@ -1162,8 +1185,13 @@ def __repr__(self):
11621185
return "\n".join(map(lambda x: fmt % x, res))
11631186

11641187

1165-
class TLSSession(DefaultSession):
1188+
class TLSSession(TCPSession):
11661189
def __init__(self, *args, **kwargs):
1190+
# XXX this doesn't bring any value.
1191+
warning(
1192+
"TLSSession is deprecated and will be removed in a future version. "
1193+
"Please use TCPSession instead with conf.tls_session_enable=True"
1194+
)
11671195
server_rsa_key = kwargs.pop("server_rsa_key", None)
11681196
super(TLSSession, self).__init__(*args, **kwargs)
11691197
self._old_conf_status = conf.tls_session_enable

scapy/sessions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ def _process_packet(self, pkt):
355355
packet = None # type: Optional[Packet]
356356
if data.full():
357357
# Reassemble using all previous packets
358+
metadata["original"] = pkt
358359
packet = tcp_reassemble(
359360
bytes(data),
360361
metadata,
5.53 KB
Binary file not shown.

test/tls.uts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,3 +1590,28 @@ if shutil.which("editcap"):
15901590
assert b"GET /secret.txt HTTP/1.0\n" in packets[11].msg[0].data
15911591
assert b"z2|gxarIKOxt,G1d>.Q2MzGY[k@" in packets[13].msg[0].data
15921592
conf = bck_conf
1593+
1594+
= pcap file & external TLS Key Log file with TCPSession
1595+
* GH3722
1596+
1597+
load_layer("tls")
1598+
from scapy.tools.UTscapy import scapy_path
1599+
1600+
# Write SSLKEYLOGFILE
1601+
temp_sslkeylog = get_temp_file()
1602+
with open(temp_sslkeylog, "w") as fd:
1603+
fd.write("CLIENT_RANDOM 09F91DA01B1FEB50B691C932959111E5E1D676437F7A42DE47EA881F6295D4E7 EE119869B732F0F9561FFDD95E50A2ACBF268EE0C7C33B409E68C1972E0B280944F7345E845E82F909CCFEB61C456E1F\n")
1604+
1605+
bck_conf = conf
1606+
conf.tls_session_enable = True
1607+
conf.tls_nss_filename = temp_sslkeylog
1608+
1609+
packets = sniff(offline=scapy_path("test/pcaps/tls_tcp_frag_withnss.pcap.gz"), session=TCPSession)
1610+
1611+
# XXXXXXXXXXXXXXXXXX
1612+
# WIP WIP WIP
1613+
# DO NOT MERGE
1614+
# WIP WIP WIP
1615+
# XXXXXXXXXXXXXXXXXX
1616+
1617+
conf = bck_conf

test/tls13.uts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,8 @@ assert len(ch.client_shares[0].key_exchange) == 97
12141214

12151215
= Parse TLS 1.3 Client Hello with non-rfc 5077 ticket
12161216

1217+
from scapy.layers.tls.keyexchange_tls13 import TLS_Ext_PreSharedKey_CH
1218+
12171219
ch = TLS(b'\x16\x03\x01\x01\x1a\x01\x00\x01\x16\x03\x03\xec\x9c>\xb2\x9e|B\x05\x17f\x86\xc8\x18\x0421\x87\x87\x12\xf6\xec\xa2J\x95\x84[\xf8\xab\xe9gK> \xc6%\xff&wn)\xb2\xf5\xe8_x\x96\xe9\nEsK\xda\x86o\x82f\xa5\xbadk\xf4Ar~}\x00\x08\x13\x02\x13\x03\x13\x01\x00\xff\x01\x00\x00\xc5\x00\x0b\x00\x04\x03\x00\x01\x02\x00\n\x00\x16\x00\x14\x00\x1d\x00\x17\x00\x1e\x00\x19\x00\x18\x01\x00\x01\x01\x01\x02\x01\x03\x01\x04\x00#\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\r\x00\x1e\x00\x1c\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\x00+\x00\x03\x02\x03\x04\x00-\x00\x02\x01\x01\x003\x00&\x00$\x00\x1d\x00 l\x19\xe1f1 )6\xbf\x91\x9e\xab\xd2\x06\x16\x0b|\x88\xf7,\xf1\x88\x99Z\xb6\xb3\x93\xe4\x08z\x8a\t\x00)\x00:\x00\x15\x00\x0fClient_identity\x00\x00\x00\x00\x00! m\xf3^\xc1l\xac5\xf2\xe3=\xeb\xe3\x81\xd3\xb3\xdd\xbd\xbd\x01\xc9\xdd\x01i\x8c1\xa0ye\xcd\x04\x9e\x9c')
12181220

12191221
assert isinstance(ch.msg[0].ext[9], TLS_Ext_PreSharedKey_CH)

0 commit comments

Comments
 (0)