esp32_bluetooth_classic_sni.../libs/scapy/layers/tls/extensions.py
Matheus Eduardo Garbelini 86890704fd initial commit
todo: add documentation & wireshark dissector
2021-08-31 19:51:03 +08:00

834 lines
34 KiB
Python
Executable file

# This file is part of Scapy
# Copyright (C) 2017 Maxence Tury
# This program is published under a GPLv2 license
"""
TLS handshake extensions.
"""
from __future__ import print_function
import os
import struct
from scapy.fields import ByteEnumField, ByteField, EnumField, FieldLenField, \
FieldListField, IntField, PacketField, PacketListField, ShortEnumField, \
ShortField, StrFixedLenField, StrLenField, XStrLenField
from scapy.packet import Packet, Raw, Padding
from scapy.layers.x509 import X509_Extensions
from scapy.layers.tls.basefields import _tls_version
from scapy.layers.tls.keyexchange import (SigAndHashAlgsLenField,
SigAndHashAlgsField, _tls_hash_sig)
from scapy.layers.tls.session import _GenericTLSSessionInheritance
from scapy.layers.tls.crypto.groups import _tls_named_groups
from scapy.layers.tls.crypto.suites import _tls_cipher_suites
from scapy.themes import AnsiColorTheme
from scapy.compat import raw
from scapy.config import conf
# Because ServerHello and HelloRetryRequest have the same
# msg_type, the only way to distinguish these message is by
# checking the random_bytes. If the random_bytes are equal to
# SHA256('HelloRetryRequest') then we know this is a
# HelloRetryRequest and the TLS_Ext_KeyShare must be parsed as
# TLS_Ext_KeyShare_HRR and not as TLS_Ext_KeyShare_SH
# from cryptography.hazmat.backends import default_backend
# from cryptography.hazmat.primitives import hashes
# digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
# digest.update(b"HelloRetryRequest")
# _tls_hello_retry_magic = digest.finalize()
_tls_hello_retry_magic = (
b'\xcf!\xadt\xe5\x9aa\x11\xbe\x1d\x8c\x02\x1ee\xb8\x91\xc2\xa2\x11'
b'\x16z\xbb\x8c^\x07\x9e\t\xe2\xc8\xa83\x9c'
)
_tls_ext = {0: "server_name", # RFC 4366
1: "max_fragment_length", # RFC 4366
2: "client_certificate_url", # RFC 4366
3: "trusted_ca_keys", # RFC 4366
4: "truncated_hmac", # RFC 4366
5: "status_request", # RFC 4366
6: "user_mapping", # RFC 4681
7: "client_authz", # RFC 5878
8: "server_authz", # RFC 5878
9: "cert_type", # RFC 6091
# 10: "elliptic_curves", # RFC 4492
10: "supported_groups",
11: "ec_point_formats", # RFC 4492
13: "signature_algorithms", # RFC 5246
0x0f: "heartbeat", # RFC 6520
0x10: "alpn", # RFC 7301
0x12: "signed_certificate_timestamp", # RFC 6962
0x13: "client_certificate_type", # RFC 7250
0x14: "server_certificate_type", # RFC 7250
0x15: "padding", # RFC 7685
0x16: "encrypt_then_mac", # RFC 7366
0x17: "extended_master_secret", # RFC 7627
0x1c: "record_size_limit", # RFC 8449
0x23: "session_ticket", # RFC 5077
0x29: "pre_shared_key",
0x2a: "early_data_indication",
0x2b: "supported_versions",
0x2c: "cookie",
0x2d: "psk_key_exchange_modes",
0x2f: "certificate_authorities",
0x30: "oid_filters",
0x31: "post_handshake_auth",
0x32: "signature_algorithms_cert",
0x33: "key_share",
0x3374: "next_protocol_negotiation",
# RFC-draft-agl-tls-nextprotoneg-03
0xff01: "renegotiation_info", # RFC 5746
0xffce: "encrypted_server_name"
}
class TLS_Ext_Unknown(_GenericTLSSessionInheritance):
"""
We put this here rather than in extensions.py in order to avoid
circular imports...
"""
name = "TLS Extension - Scapy Unknown"
fields_desc = [ShortEnumField("type", None, _tls_ext),
FieldLenField("len", None, fmt="!H", length_of="val"),
StrLenField("val", "",
length_from=lambda pkt: pkt.len)]
def post_build(self, p, pay):
if self.len is None:
tmp_len = len(p) - 4
p = p[:2] + struct.pack("!H", tmp_len) + p[4:]
return p + pay
###############################################################################
# ClientHello/ServerHello extensions #
###############################################################################
# We provide these extensions mostly for packet manipulation purposes.
# For now, most of them are not considered by our automaton.
class TLS_Ext_PrettyPacketList(TLS_Ext_Unknown):
"""
Dummy extension used for server_name/ALPN/NPN for a lighter representation:
the final field is showed as a 1-line list rather than as lots of packets.
XXX Define a new condition for packet lists in Packet._show_or_dump?
"""
def _show_or_dump(self, dump=False, indent=3,
lvl="", label_lvl="", first_call=True):
""" Reproduced from packet.py """
ct = AnsiColorTheme() if dump else conf.color_theme
s = "%s%s %s %s \n" % (label_lvl, ct.punct("###["),
ct.layer_name(self.name), ct.punct("]###"))
for f in self.fields_desc[:-1]:
ncol = ct.field_name
vcol = ct.field_value
fvalue = self.getfieldval(f.name)
begn = "%s %-10s%s " % (label_lvl + lvl, ncol(f.name),
ct.punct("="),)
reprval = f.i2repr(self, fvalue)
if isinstance(reprval, str):
reprval = reprval.replace("\n", "\n" + " " * (len(label_lvl) +
len(lvl) +
len(f.name) +
4))
s += "%s%s\n" % (begn, vcol(reprval))
f = self.fields_desc[-1]
ncol = ct.field_name
vcol = ct.field_value
fvalue = self.getfieldval(f.name)
begn = "%s %-10s%s " % (label_lvl + lvl, ncol(f.name), ct.punct("="),)
reprval = f.i2repr(self, fvalue)
if isinstance(reprval, str):
reprval = reprval.replace("\n", "\n" + " " * (len(label_lvl) +
len(lvl) +
len(f.name) +
4))
s += "%s%s\n" % (begn, vcol(reprval))
if self.payload:
s += self.payload._show_or_dump(dump=dump, indent=indent,
lvl=lvl + (" " * indent * self.show_indent), # noqa: E501
label_lvl=label_lvl, first_call=False) # noqa: E501
if first_call and not dump:
print(s)
else:
return s
_tls_server_name_types = {0: "host_name"}
class ServerName(Packet):
name = "HostName"
fields_desc = [ByteEnumField("nametype", 0, _tls_server_name_types),
FieldLenField("namelen", None, length_of="servername"),
StrLenField("servername", "",
length_from=lambda pkt: pkt.namelen)]
def guess_payload_class(self, p):
return Padding
class ServerListField(PacketListField):
def i2repr(self, pkt, x):
res = [p.servername for p in x]
return "[%s]" % b", ".join(res)
class ServerLenField(FieldLenField):
"""
There is no length when there are no servernames (as in a ServerHello).
"""
def addfield(self, pkt, s, val):
if not val:
if not pkt.servernames:
return s
return super(ServerLenField, self).addfield(pkt, s, val)
class TLS_Ext_ServerName(TLS_Ext_PrettyPacketList): # RFC 4366
name = "TLS Extension - Server Name"
fields_desc = [ShortEnumField("type", 0, _tls_ext),
FieldLenField("len", None, length_of="servernames",
adjust=lambda pkt, x: x + 2),
ServerLenField("servernameslen", None,
length_of="servernames"),
ServerListField("servernames", [], ServerName,
length_from=lambda pkt: pkt.servernameslen)]
class TLS_Ext_EncryptedServerName(TLS_Ext_PrettyPacketList):
name = "TLS Extension - Encrypted Server Name"
fields_desc = [ShortEnumField("type", 0xffce, _tls_ext),
ShortField("len", None),
EnumField("cipher", None, _tls_cipher_suites),
ShortEnumField("key_exchange_group", None,
_tls_named_groups),
FieldLenField("key_exchange_len", None,
length_of="key_exchange", fmt="H"),
XStrLenField("key_exchange", "",
length_from=lambda pkt: pkt.key_exchange_len),
FieldLenField("record_digest_len",
None, length_of="record_digest"),
XStrLenField("record_digest", "",
length_from=lambda pkt: pkt.record_digest_len),
FieldLenField("encrypted_sni_len", None,
length_of="encrypted_sni", fmt="H"),
XStrLenField("encrypted_sni", "",
length_from=lambda pkt: pkt.encrypted_sni_len)]
class TLS_Ext_MaxFragLen(TLS_Ext_Unknown): # RFC 4366
name = "TLS Extension - Max Fragment Length"
fields_desc = [ShortEnumField("type", 1, _tls_ext),
ShortField("len", None),
ByteEnumField("maxfraglen", 4, {1: "2^9",
2: "2^10",
3: "2^11",
4: "2^12"})]
class TLS_Ext_ClientCertURL(TLS_Ext_Unknown): # RFC 4366
name = "TLS Extension - Client Certificate URL"
fields_desc = [ShortEnumField("type", 2, _tls_ext),
ShortField("len", None)]
_tls_trusted_authority_types = {0: "pre_agreed",
1: "key_sha1_hash",
2: "x509_name",
3: "cert_sha1_hash"}
class TAPreAgreed(Packet):
name = "Trusted authority - pre_agreed"
fields_desc = [ByteEnumField("idtype", 0, _tls_trusted_authority_types)]
def guess_payload_class(self, p):
return Padding
class TAKeySHA1Hash(Packet):
name = "Trusted authority - key_sha1_hash"
fields_desc = [ByteEnumField("idtype", 1, _tls_trusted_authority_types),
StrFixedLenField("id", None, 20)]
def guess_payload_class(self, p):
return Padding
class TAX509Name(Packet):
"""
XXX Section 3.4 of RFC 4366. Implement a more specific DNField
rather than current StrLenField.
"""
name = "Trusted authority - x509_name"
fields_desc = [ByteEnumField("idtype", 2, _tls_trusted_authority_types),
FieldLenField("dnlen", None, length_of="dn"),
StrLenField("dn", "", length_from=lambda pkt: pkt.dnlen)]
def guess_payload_class(self, p):
return Padding
class TACertSHA1Hash(Packet):
name = "Trusted authority - cert_sha1_hash"
fields_desc = [ByteEnumField("idtype", 3, _tls_trusted_authority_types),
StrFixedLenField("id", None, 20)]
def guess_payload_class(self, p):
return Padding
_tls_trusted_authority_cls = {0: TAPreAgreed,
1: TAKeySHA1Hash,
2: TAX509Name,
3: TACertSHA1Hash}
class _TAListField(PacketListField):
"""
Specific version that selects the right Trusted Authority (previous TA*)
class to be used for dissection based on idtype.
"""
def m2i(self, pkt, m):
idtype = ord(m[0])
cls = self.cls
if idtype in _tls_trusted_authority_cls:
cls = _tls_trusted_authority_cls[idtype]
return cls(m)
class TLS_Ext_TrustedCAInd(TLS_Ext_Unknown): # RFC 4366
name = "TLS Extension - Trusted CA Indication"
fields_desc = [ShortEnumField("type", 3, _tls_ext),
ShortField("len", None),
FieldLenField("talen", None, length_of="ta"),
_TAListField("ta", [], Raw,
length_from=lambda pkt: pkt.talen)]
class TLS_Ext_TruncatedHMAC(TLS_Ext_Unknown): # RFC 4366
name = "TLS Extension - Truncated HMAC"
fields_desc = [ShortEnumField("type", 4, _tls_ext),
ShortField("len", None)]
class ResponderID(Packet):
name = "Responder ID structure"
fields_desc = [FieldLenField("respidlen", None, length_of="respid"),
StrLenField("respid", "",
length_from=lambda pkt: pkt.respidlen)]
def guess_payload_class(self, p):
return Padding
class OCSPStatusRequest(Packet):
"""
This is the structure defined in RFC 6066, not in RFC 6960!
"""
name = "OCSPStatusRequest structure"
fields_desc = [FieldLenField("respidlen", None, length_of="respid"),
PacketListField("respid", [], ResponderID,
length_from=lambda pkt: pkt.respidlen),
FieldLenField("reqextlen", None, length_of="reqext"),
PacketField("reqext", "", X509_Extensions)]
def guess_payload_class(self, p):
return Padding
_cert_status_type = {1: "ocsp"}
_cert_status_req_cls = {1: OCSPStatusRequest}
class _StatusReqField(PacketListField):
def m2i(self, pkt, m):
idtype = pkt.stype
cls = self.cls
if idtype in _cert_status_req_cls:
cls = _cert_status_req_cls[idtype]
return cls(m)
class TLS_Ext_CSR(TLS_Ext_Unknown): # RFC 4366
name = "TLS Extension - Certificate Status Request"
fields_desc = [ShortEnumField("type", 5, _tls_ext),
ShortField("len", None),
ByteEnumField("stype", None, _cert_status_type),
_StatusReqField("req", [], Raw,
length_from=lambda pkt: pkt.len - 1)]
class TLS_Ext_UserMapping(TLS_Ext_Unknown): # RFC 4681
name = "TLS Extension - User Mapping"
fields_desc = [ShortEnumField("type", 6, _tls_ext),
ShortField("len", None),
FieldLenField("umlen", None, fmt="B", length_of="um"),
FieldListField("um", [],
ByteField("umtype", 0),
length_from=lambda pkt: pkt.umlen)]
class TLS_Ext_ClientAuthz(TLS_Ext_Unknown): # RFC 5878
""" XXX Unsupported """
name = "TLS Extension - Client Authz"
fields_desc = [ShortEnumField("type", 7, _tls_ext),
ShortField("len", None),
]
class TLS_Ext_ServerAuthz(TLS_Ext_Unknown): # RFC 5878
""" XXX Unsupported """
name = "TLS Extension - Server Authz"
fields_desc = [ShortEnumField("type", 8, _tls_ext),
ShortField("len", None),
]
_tls_cert_types = {0: "X.509", 1: "OpenPGP"}
class TLS_Ext_ClientCertType(TLS_Ext_Unknown): # RFC 5081
name = "TLS Extension - Certificate Type (client version)"
fields_desc = [ShortEnumField("type", 9, _tls_ext),
ShortField("len", None),
FieldLenField("ctypeslen", None, length_of="ctypes"),
FieldListField("ctypes", [0, 1],
ByteEnumField("certtypes", None,
_tls_cert_types),
length_from=lambda pkt: pkt.ctypeslen)]
class TLS_Ext_ServerCertType(TLS_Ext_Unknown): # RFC 5081
name = "TLS Extension - Certificate Type (server version)"
fields_desc = [ShortEnumField("type", 9, _tls_ext),
ShortField("len", None),
ByteEnumField("ctype", None, _tls_cert_types)]
def _TLS_Ext_CertTypeDispatcher(m, *args, **kargs):
"""
We need to select the correct one on dissection. We use the length for
that, as 1 for client version would emply an empty list.
"""
tmp_len = struct.unpack("!H", m[2:4])[0]
if tmp_len == 1:
cls = TLS_Ext_ServerCertType
else:
cls = TLS_Ext_ClientCertType
return cls(m, *args, **kargs)
class TLS_Ext_SupportedGroups(TLS_Ext_Unknown):
"""
This extension was known as 'Supported Elliptic Curves' before TLS 1.3
merged both group selection mechanisms for ECDH and FFDH.
"""
name = "TLS Extension - Supported Groups"
fields_desc = [ShortEnumField("type", 10, _tls_ext),
ShortField("len", None),
FieldLenField("groupslen", None, length_of="groups"),
FieldListField("groups", [],
ShortEnumField("ng", None,
_tls_named_groups),
length_from=lambda pkt: pkt.groupslen)]
class TLS_Ext_SupportedEllipticCurves(TLS_Ext_SupportedGroups): # RFC 4492
pass
_tls_ecpoint_format = {0: "uncompressed",
1: "ansiX962_compressed_prime",
2: "ansiX962_compressed_char2"}
class TLS_Ext_SupportedPointFormat(TLS_Ext_Unknown): # RFC 4492
name = "TLS Extension - Supported Point Format"
fields_desc = [ShortEnumField("type", 11, _tls_ext),
ShortField("len", None),
FieldLenField("ecpllen", None, fmt="B", length_of="ecpl"),
FieldListField("ecpl", [0],
ByteEnumField("nc", None,
_tls_ecpoint_format),
length_from=lambda pkt: pkt.ecpllen)]
class TLS_Ext_SignatureAlgorithms(TLS_Ext_Unknown): # RFC 5246
name = "TLS Extension - Signature Algorithms"
fields_desc = [ShortEnumField("type", 13, _tls_ext),
ShortField("len", None),
SigAndHashAlgsLenField("sig_algs_len", None,
length_of="sig_algs"),
SigAndHashAlgsField("sig_algs", [],
EnumField("hash_sig", None,
_tls_hash_sig),
length_from=lambda pkt: pkt.sig_algs_len)] # noqa: E501
class TLS_Ext_Heartbeat(TLS_Ext_Unknown): # RFC 6520
name = "TLS Extension - Heartbeat"
fields_desc = [ShortEnumField("type", 0x0f, _tls_ext),
ShortField("len", None),
ByteEnumField("heartbeat_mode", 2,
{1: "peer_allowed_to_send",
2: "peer_not_allowed_to_send"})]
class ProtocolName(Packet):
name = "Protocol Name"
fields_desc = [FieldLenField("len", None, fmt='B', length_of="protocol"),
StrLenField("protocol", "",
length_from=lambda pkt: pkt.len)]
def guess_payload_class(self, p):
return Padding
class ProtocolListField(PacketListField):
def i2repr(self, pkt, x):
res = [p.protocol for p in x]
return "[%s]" % b", ".join(res)
class TLS_Ext_ALPN(TLS_Ext_PrettyPacketList): # RFC 7301
name = "TLS Extension - Application Layer Protocol Negotiation"
fields_desc = [ShortEnumField("type", 0x10, _tls_ext),
ShortField("len", None),
FieldLenField("protocolslen", None, length_of="protocols"),
ProtocolListField("protocols", [], ProtocolName,
length_from=lambda pkt:pkt.protocolslen)]
class TLS_Ext_Padding(TLS_Ext_Unknown): # RFC 7685
name = "TLS Extension - Padding"
fields_desc = [ShortEnumField("type", 0x15, _tls_ext),
FieldLenField("len", None, length_of="padding"),
StrLenField("padding", "",
length_from=lambda pkt: pkt.len)]
class TLS_Ext_EncryptThenMAC(TLS_Ext_Unknown): # RFC 7366
name = "TLS Extension - Encrypt-then-MAC"
fields_desc = [ShortEnumField("type", 0x16, _tls_ext),
ShortField("len", None)]
class TLS_Ext_ExtendedMasterSecret(TLS_Ext_Unknown): # RFC 7627
name = "TLS Extension - Extended Master Secret"
fields_desc = [ShortEnumField("type", 0x17, _tls_ext),
ShortField("len", None)]
class TLS_Ext_SessionTicket(TLS_Ext_Unknown): # RFC 5077
"""
RFC 5077 updates RFC 4507 according to most implementations, which do not
use another (useless) 'ticketlen' field after the global 'len' field.
"""
name = "TLS Extension - Session Ticket"
fields_desc = [ShortEnumField("type", 0x23, _tls_ext),
FieldLenField("len", None, length_of="ticket"),
StrLenField("ticket", "",
length_from=lambda pkt: pkt.len)]
class TLS_Ext_KeyShare(TLS_Ext_Unknown):
name = "TLS Extension - Key Share (dummy class)"
fields_desc = [ShortEnumField("type", 0x33, _tls_ext),
ShortField("len", None)]
class TLS_Ext_PreSharedKey(TLS_Ext_Unknown):
name = "TLS Extension - Pre Shared Key (dummy class)"
fields_desc = [ShortEnumField("type", 0x29, _tls_ext),
ShortField("len", None)]
class TLS_Ext_EarlyDataIndication(TLS_Ext_Unknown):
name = "TLS Extension - Early Data"
fields_desc = [ShortEnumField("type", 0x2a, _tls_ext),
ShortField("len", None)]
class TLS_Ext_EarlyDataIndicationTicket(TLS_Ext_Unknown):
name = "TLS Extension - Ticket Early Data Info"
fields_desc = [ShortEnumField("type", 0x2a, _tls_ext),
ShortField("len", None),
IntField("max_early_data_size", 0)]
_tls_ext_early_data_cls = {1: TLS_Ext_EarlyDataIndication,
4: TLS_Ext_EarlyDataIndicationTicket,
8: TLS_Ext_EarlyDataIndication}
class TLS_Ext_SupportedVersions(TLS_Ext_Unknown):
name = "TLS Extension - Supported Versions (dummy class)"
fields_desc = [ShortEnumField("type", 0x2b, _tls_ext),
ShortField("len", None)]
class TLS_Ext_SupportedVersion_CH(TLS_Ext_Unknown):
name = "TLS Extension - Supported Versions (for ClientHello)"
fields_desc = [ShortEnumField("type", 0x2b, _tls_ext),
ShortField("len", None),
FieldLenField("versionslen", None, fmt='B',
length_of="versions"),
FieldListField("versions", [],
ShortEnumField("version", None,
_tls_version),
length_from=lambda pkt: pkt.versionslen)]
class TLS_Ext_SupportedVersion_SH(TLS_Ext_Unknown):
name = "TLS Extension - Supported Versions (for ServerHello)"
fields_desc = [ShortEnumField("type", 0x2b, _tls_ext),
ShortField("len", None),
ShortEnumField("version", None, _tls_version)]
_tls_ext_supported_version_cls = {1: TLS_Ext_SupportedVersion_CH,
2: TLS_Ext_SupportedVersion_SH}
class TLS_Ext_Cookie(TLS_Ext_Unknown):
name = "TLS Extension - Cookie"
fields_desc = [ShortEnumField("type", 0x2c, _tls_ext),
ShortField("len", None),
FieldLenField("cookielen", None, length_of="cookie"),
XStrLenField("cookie", "",
length_from=lambda pkt: pkt.cookielen)]
def build(self):
fval = self.getfieldval("cookie")
if fval is None or fval == b"":
self.cookie = os.urandom(32)
return TLS_Ext_Unknown.build(self)
_tls_psk_kx_modes = {0: "psk_ke", 1: "psk_dhe_ke"}
class TLS_Ext_PSKKeyExchangeModes(TLS_Ext_Unknown):
name = "TLS Extension - PSK Key Exchange Modes"
fields_desc = [ShortEnumField("type", 0x2d, _tls_ext),
ShortField("len", None),
FieldLenField("kxmodeslen", None, fmt='B',
length_of="kxmodes"),
FieldListField("kxmodes", [],
ByteEnumField("kxmode", None,
_tls_psk_kx_modes),
length_from=lambda pkt: pkt.kxmodeslen)]
class TLS_Ext_TicketEarlyDataInfo(TLS_Ext_Unknown):
name = "TLS Extension - Ticket Early Data Info"
fields_desc = [ShortEnumField("type", 0x2e, _tls_ext),
ShortField("len", None),
IntField("max_early_data_size", 0)]
class TLS_Ext_NPN(TLS_Ext_PrettyPacketList):
"""
Defined in RFC-draft-agl-tls-nextprotoneg-03. Deprecated in favour of ALPN.
"""
name = "TLS Extension - Next Protocol Negotiation"
fields_desc = [ShortEnumField("type", 0x3374, _tls_ext),
FieldLenField("len", None, length_of="protocols"),
ProtocolListField("protocols", [], ProtocolName,
length_from=lambda pkt:pkt.len)]
class TLS_Ext_PostHandshakeAuth(TLS_Ext_Unknown): # RFC 8446
name = "TLS Extension - Post Handshake Auth"
fields_desc = [ShortEnumField("type", 0x31, _tls_ext),
ShortField("len", None)]
class TLS_Ext_SignatureAlgorithmsCert(TLS_Ext_Unknown): # RFC 8446
name = "TLS Extension - Signature Algorithms Cert"
fields_desc = [ShortEnumField("type", 0x31, _tls_ext),
ShortField("len", None),
SigAndHashAlgsLenField("sig_algs_len", None,
length_of="sig_algs"),
SigAndHashAlgsField("sig_algs", [],
EnumField("hash_sig", None,
_tls_hash_sig),
length_from=lambda pkt: pkt.sig_algs_len)] # noqa: E501
class TLS_Ext_RenegotiationInfo(TLS_Ext_Unknown): # RFC 5746
name = "TLS Extension - Renegotiation Indication"
fields_desc = [ShortEnumField("type", 0xff01, _tls_ext),
ShortField("len", None),
FieldLenField("reneg_conn_len", None, fmt='B',
length_of="renegotiated_connection"),
StrLenField("renegotiated_connection", "",
length_from=lambda pkt: pkt.reneg_conn_len)]
class TLS_Ext_RecordSizeLimit(TLS_Ext_Unknown): # RFC 8449
name = "TLS Extension - Record Size Limit"
fields_desc = [ShortEnumField("type", 0x1c, _tls_ext),
ShortField("len", None),
ShortField("record_size_limit", None)]
_tls_ext_cls = {0: TLS_Ext_ServerName,
1: TLS_Ext_MaxFragLen,
2: TLS_Ext_ClientCertURL,
3: TLS_Ext_TrustedCAInd,
4: TLS_Ext_TruncatedHMAC,
5: TLS_Ext_CSR,
6: TLS_Ext_UserMapping,
7: TLS_Ext_ClientAuthz,
8: TLS_Ext_ServerAuthz,
9: _TLS_Ext_CertTypeDispatcher,
# 10: TLS_Ext_SupportedEllipticCurves,
10: TLS_Ext_SupportedGroups,
11: TLS_Ext_SupportedPointFormat,
13: TLS_Ext_SignatureAlgorithms,
0x0f: TLS_Ext_Heartbeat,
0x10: TLS_Ext_ALPN,
0x15: TLS_Ext_Padding,
0x16: TLS_Ext_EncryptThenMAC,
0x17: TLS_Ext_ExtendedMasterSecret,
0x1c: TLS_Ext_RecordSizeLimit,
0x23: TLS_Ext_SessionTicket,
# 0x28: TLS_Ext_KeyShare,
0x29: TLS_Ext_PreSharedKey,
0x2a: TLS_Ext_EarlyDataIndication,
0x2b: TLS_Ext_SupportedVersions,
0x2c: TLS_Ext_Cookie,
0x2d: TLS_Ext_PSKKeyExchangeModes,
# 0x2e: TLS_Ext_TicketEarlyDataInfo,
0x31: TLS_Ext_PostHandshakeAuth,
0x32: TLS_Ext_SignatureAlgorithmsCert,
0x33: TLS_Ext_KeyShare,
# 0x2f: TLS_Ext_CertificateAuthorities, #XXX
# 0x30: TLS_Ext_OIDFilters, #XXX
0x3374: TLS_Ext_NPN,
0xff01: TLS_Ext_RenegotiationInfo,
0xffce: TLS_Ext_EncryptedServerName
}
class _ExtensionsLenField(FieldLenField):
def getfield(self, pkt, s):
"""
We try to compute a length, usually from a msglen parsed earlier.
If this length is 0, we consider 'selection_present' (from RFC 5246)
to be False. This means that there should not be any length field.
However, with TLS 1.3, zero lengths are always explicit.
"""
ext = pkt.get_field(self.length_of)
tmp_len = ext.length_from(pkt)
if tmp_len is None or tmp_len <= 0:
v = pkt.tls_session.tls_version
if v is None or v < 0x0304:
return s, None
return super(_ExtensionsLenField, self).getfield(pkt, s)
def addfield(self, pkt, s, i):
"""
There is a hack with the _ExtensionsField.i2len. It works only because
we expect _ExtensionsField.i2m to return a string of the same size (if
not of the same value) upon successive calls (e.g. through i2len here,
then i2m when directly building the _ExtensionsField).
XXX A proper way to do this would be to keep the extensions built from
the i2len call here, instead of rebuilding them later on.
"""
if i is None:
if self.length_of is not None:
fld, fval = pkt.getfield_and_val(self.length_of)
tmp = pkt.tls_session.frozen
pkt.tls_session.frozen = True
f = fld.i2len(pkt, fval)
pkt.tls_session.frozen = tmp
i = self.adjust(pkt, f)
if i == 0: # for correct build if no ext and not explicitly 0
v = pkt.tls_session.tls_version
# Xith TLS 1.3, zero lengths are always explicit.
if v is None or v < 0x0304:
return s
else:
return s + struct.pack(self.fmt, i)
return s + struct.pack(self.fmt, i)
class _ExtensionsField(StrLenField):
islist = 1
holds_packets = 1
def i2len(self, pkt, i):
if i is None:
return 0
return len(self.i2m(pkt, i))
def getfield(self, pkt, s):
tmp_len = self.length_from(pkt)
if tmp_len is None:
return s, []
return s[tmp_len:], self.m2i(pkt, s[:tmp_len])
def i2m(self, pkt, i):
if i is None:
return b""
if isinstance(pkt, _GenericTLSSessionInheritance):
if not pkt.tls_session.frozen:
s = b""
for ext in i:
if isinstance(ext, _GenericTLSSessionInheritance):
ext.tls_session = pkt.tls_session
s += ext.raw_stateful()
else:
s += raw(ext)
return s
return b"".join(map(raw, i))
def m2i(self, pkt, m):
res = []
while len(m) >= 4:
t = struct.unpack("!H", m[:2])[0]
tmp_len = struct.unpack("!H", m[2:4])[0]
cls = _tls_ext_cls.get(t, TLS_Ext_Unknown)
if cls is TLS_Ext_KeyShare:
# TLS_Ext_KeyShare can be :
# - TLS_Ext_KeyShare_CH if the message is a ClientHello
# - TLS_Ext_KeyShare_SH if the message is a ServerHello
# and all parameters are accepted by the serveur
# - TLS_Ext_KeyShare_HRR if message is a ServerHello and
# the client has not provided a sufficient "key_share"
# extension
from scapy.layers.tls.keyexchange_tls13 import (
_tls_ext_keyshare_cls, _tls_ext_keyshare_hrr_cls)
# If SHA-256("HelloRetryRequest") == server_random,
# this message is a HelloRetryRequest
if pkt.random_bytes and \
pkt.random_bytes == _tls_hello_retry_magic:
cls = _tls_ext_keyshare_hrr_cls.get(pkt.msgtype, TLS_Ext_Unknown) # noqa: E501
else:
cls = _tls_ext_keyshare_cls.get(pkt.msgtype, TLS_Ext_Unknown) # noqa: E501
elif cls is TLS_Ext_PreSharedKey:
from scapy.layers.tls.keyexchange_tls13 import _tls_ext_presharedkey_cls # noqa: E501
cls = _tls_ext_presharedkey_cls.get(pkt.msgtype, TLS_Ext_Unknown) # noqa: E501
elif cls is TLS_Ext_SupportedVersions:
cls = _tls_ext_supported_version_cls.get(pkt.msgtype, TLS_Ext_Unknown) # noqa: E501
elif cls is TLS_Ext_EarlyDataIndication:
cls = _tls_ext_early_data_cls.get(pkt.msgtype, TLS_Ext_Unknown)
res.append(cls(m[:tmp_len + 4], tls_session=pkt.tls_session))
m = m[tmp_len + 4:]
return res