Skip to content

Commit aecd423

Browse files
committed
tls: fix TLS_Ext_KeyShare_SH server_share consuming trailing extensions
PacketField has no length bound, so server_share greedily consumed all remaining bytes including subsequent extensions. Switch to PacketLenField with length_from=pkt.len to bound dissection to the extension's own length field.
1 parent 8b50806 commit aecd423

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

scapy/layers/tls/keyexchange_tls13.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ class TLS_Ext_KeyShare_SH(TLS_Ext_Unknown):
157157
name = "TLS Extension - Key Share (for ServerHello)"
158158
fields_desc = [ShortEnumField("type", 0x33, _tls_ext),
159159
ShortField("len", None),
160-
PacketField("server_share", None, KeyShareEntry)]
160+
PacketLenField("server_share", None, KeyShareEntry, length_from=lambda pkt: pkt.len)]
161161

162162
def post_build(self, pkt, pay):
163163
if not self.tls_session.frozen and self.server_share.privkey:

test/scapy/layers/tls/tls13.uts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,38 @@ assert ch.len == 103
12121212
assert ch.client_shares[0].kxlen == 97
12131213
assert len(ch.client_shares[0].key_exchange) == 97
12141214

1215+
= TLS_Ext_KeyShare_SH - dissect raw bytes with PacketLenField
1216+
1217+
from scapy.layers.tls.keyexchange_tls13 import TLS_Ext_KeyShare_SH
1218+
from scapy.packet import Raw
1219+
1220+
# Raw bytes of TLS_Ext_KeyShare_SH with an x25519 server key (RFC 8448 test vector)
1221+
x25519_pub_rfc8448 = 'c9828876112095fe66762bdbf7c672e156d6cc253b833df1dd69b1b04e751f0f'
1222+
raw_ks = bytes.fromhex(
1223+
'0033' # type = key_share (0x0033)
1224+
'0024' # len = 36 (4 header + 32 key bytes)
1225+
'001d' # group = x25519 (29)
1226+
'0020' # kxlen = 32
1227+
+ x25519_pub_rfc8448
1228+
)
1229+
pkt = TLS_Ext_KeyShare_SH(raw_ks)
1230+
assert pkt.type == 0x0033
1231+
assert pkt.len == 36
1232+
assert pkt.server_share.group == 29
1233+
assert pkt.server_share.kxlen == 32
1234+
assert pkt.server_share.key_exchange == bytes.fromhex(x25519_pub_rfc8448)
1235+
1236+
# Trailing bytes (simulating a subsequent extension) must not be consumed by server_share
1237+
trailing = bytes.fromhex('002b00020304') # TLS_Ext_SupportedVersion_SH (TLS 1.3)
1238+
pkt2 = TLS_Ext_KeyShare_SH(raw_ks + trailing)
1239+
assert pkt2.server_share.group == 29
1240+
assert pkt2.server_share.kxlen == 32
1241+
assert len(pkt2.server_share.key_exchange) == 32
1242+
assert pkt2.server_share.key_exchange == bytes.fromhex(x25519_pub_rfc8448)
1243+
# Trailing bytes must be preserved as payload, not silently consumed by server_share
1244+
assert Raw in pkt2
1245+
assert pkt2[Raw].load == trailing
1246+
12151247
= Parse TLS 1.3 Client Hello with non-rfc 5077 ticket
12161248

12171249
from scapy.layers.tls.keyexchange_tls13 import TLS_Ext_PreSharedKey_CH

0 commit comments

Comments
 (0)