# 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