• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) 2017 Maxence Tury
5
6"""
7TLS handshake extensions.
8"""
9
10
11import os
12import struct
13
14from scapy.fields import (
15    ByteEnumField,
16    ByteField,
17    EnumField,
18    FieldLenField,
19    FieldListField,
20    IntField,
21    MayEnd,
22    PacketField,
23    PacketListField,
24    ShortEnumField,
25    ShortField,
26    StrFixedLenField,
27    StrLenField,
28    XStrLenField,
29)
30from scapy.packet import Packet, Raw, Padding
31from scapy.layers.x509 import X509_Extensions
32from scapy.layers.tls.basefields import _tls_version
33from scapy.layers.tls.keyexchange import (SigAndHashAlgsLenField,
34                                          SigAndHashAlgsField, _tls_hash_sig)
35from scapy.layers.tls.session import _GenericTLSSessionInheritance
36from scapy.layers.tls.crypto.groups import _tls_named_groups
37from scapy.layers.tls.crypto.suites import _tls_cipher_suites
38from scapy.themes import AnsiColorTheme
39from scapy.compat import raw
40from scapy.config import conf
41
42
43# Because ServerHello and HelloRetryRequest have the same
44# msg_type, the only way to distinguish these message is by
45# checking the random_bytes. If the random_bytes are equal to
46# SHA256('HelloRetryRequest') then we know this is a
47# HelloRetryRequest and the TLS_Ext_KeyShare must be parsed as
48# TLS_Ext_KeyShare_HRR and not as TLS_Ext_KeyShare_SH
49
50# from cryptography.hazmat.backends import default_backend
51# from cryptography.hazmat.primitives import hashes
52# digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
53# digest.update(b"HelloRetryRequest")
54# _tls_hello_retry_magic = digest.finalize()
55
56_tls_hello_retry_magic = (
57    b'\xcf!\xadt\xe5\x9aa\x11\xbe\x1d\x8c\x02\x1ee\xb8\x91\xc2\xa2\x11'
58    b'\x16z\xbb\x8c^\x07\x9e\t\xe2\xc8\xa83\x9c'
59)
60
61
62_tls_ext = {0: "server_name",             # RFC 4366
63            1: "max_fragment_length",     # RFC 4366
64            2: "client_certificate_url",  # RFC 4366
65            3: "trusted_ca_keys",         # RFC 4366
66            4: "truncated_hmac",          # RFC 4366
67            5: "status_request",          # RFC 4366
68            6: "user_mapping",            # RFC 4681
69            7: "client_authz",            # RFC 5878
70            8: "server_authz",            # RFC 5878
71            9: "cert_type",               # RFC 6091
72            # 10: "elliptic_curves",         # RFC 4492
73            10: "supported_groups",
74            11: "ec_point_formats",        # RFC 4492
75            13: "signature_algorithms",    # RFC 5246
76            0x0f: "heartbeat",             # RFC 6520
77            0x10: "alpn",                  # RFC 7301
78            0x12: "signed_certificate_timestamp",  # RFC 6962
79            0x13: "client_certificate_type",  # RFC 7250
80            0x14: "server_certificate_type",  # RFC 7250
81            0x15: "padding",               # RFC 7685
82            0x16: "encrypt_then_mac",      # RFC 7366
83            0x17: "extended_master_secret",  # RFC 7627
84            0x1c: "record_size_limit",     # RFC 8449
85            0x23: "session_ticket",        # RFC 5077
86            0x29: "pre_shared_key",
87            0x2a: "early_data_indication",
88            0x2b: "supported_versions",
89            0x2c: "cookie",
90            0x2d: "psk_key_exchange_modes",
91            0x2f: "certificate_authorities",
92            0x30: "oid_filters",
93            0x31: "post_handshake_auth",
94            0x32: "signature_algorithms_cert",
95            0x33: "key_share",
96            0x3374: "next_protocol_negotiation",
97            # RFC-draft-agl-tls-nextprotoneg-03
98            0xff01: "renegotiation_info",   # RFC 5746
99            0xffce: "encrypted_server_name"
100            }
101
102
103class TLS_Ext_Unknown(_GenericTLSSessionInheritance):
104    """
105    We put this here rather than in extensions.py in order to avoid
106    circular imports...
107    """
108    name = "TLS Extension - Scapy Unknown"
109    fields_desc = [ShortEnumField("type", None, _tls_ext),
110                   FieldLenField("len", None, fmt="!H", length_of="val"),
111                   StrLenField("val", "",
112                               length_from=lambda pkt: pkt.len)]
113
114    def post_build(self, p, pay):
115        if self.len is None:
116            tmp_len = len(p) - 4
117            p = p[:2] + struct.pack("!H", tmp_len) + p[4:]
118        return p + pay
119
120
121###############################################################################
122#   ClientHello/ServerHello extensions                                        #
123###############################################################################
124
125# We provide these extensions mostly for packet manipulation purposes.
126# For now, most of them are not considered by our automaton.
127
128class TLS_Ext_PrettyPacketList(TLS_Ext_Unknown):
129    """
130    Dummy extension used for server_name/ALPN/NPN for a lighter representation:
131    the final field is showed as a 1-line list rather than as lots of packets.
132    XXX Define a new condition for packet lists in Packet._show_or_dump?
133    """
134
135    def _show_or_dump(self, dump=False, indent=3,
136                      lvl="", label_lvl="", first_call=True):
137        """ Reproduced from packet.py """
138        ct = AnsiColorTheme() if dump else conf.color_theme
139        s = "%s%s %s %s \n" % (label_lvl, ct.punct("###["),
140                               ct.layer_name(self.name), ct.punct("]###"))
141        for f in self.fields_desc[:-1]:
142            ncol = ct.field_name
143            vcol = ct.field_value
144            fvalue = self.getfieldval(f.name)
145            begn = "%s  %-10s%s " % (label_lvl + lvl, ncol(f.name),
146                                     ct.punct("="),)
147            reprval = f.i2repr(self, fvalue)
148            if isinstance(reprval, str):
149                reprval = reprval.replace("\n", "\n" + " " * (len(label_lvl) +
150                                                              len(lvl) +
151                                                              len(f.name) +
152                                                              4))
153            s += "%s%s\n" % (begn, vcol(reprval))
154        f = self.fields_desc[-1]
155        ncol = ct.field_name
156        vcol = ct.field_value
157        fvalue = self.getfieldval(f.name)
158        begn = "%s  %-10s%s " % (label_lvl + lvl, ncol(f.name), ct.punct("="),)
159        reprval = f.i2repr(self, fvalue)
160        if isinstance(reprval, str):
161            reprval = reprval.replace("\n", "\n" + " " * (len(label_lvl) +
162                                                          len(lvl) +
163                                                          len(f.name) +
164                                                          4))
165        s += "%s%s\n" % (begn, vcol(reprval))
166        if self.payload:
167            s += self.payload._show_or_dump(dump=dump, indent=indent,
168                                            lvl=lvl + (" " * indent * self.show_indent),  # noqa: E501
169                                            label_lvl=label_lvl, first_call=False)  # noqa: E501
170
171        if first_call and not dump:
172            print(s)
173        else:
174            return s
175
176
177_tls_server_name_types = {0: "host_name"}
178
179
180class ServerName(Packet):
181    name = "HostName"
182    fields_desc = [ByteEnumField("nametype", 0, _tls_server_name_types),
183                   FieldLenField("namelen", None, length_of="servername"),
184                   StrLenField("servername", "",
185                               length_from=lambda pkt: pkt.namelen)]
186
187    def guess_payload_class(self, p):
188        return Padding
189
190
191class ServerListField(PacketListField):
192    def i2repr(self, pkt, x):
193        res = [p.servername for p in x]
194        return "[%s]" % ", ".join(repr(x) for x in res)
195
196
197class ServerLenField(FieldLenField):
198    """
199    There is no length when there are no servernames (as in a ServerHello).
200    """
201
202    def addfield(self, pkt, s, val):
203        if not val:
204            if not pkt.servernames:
205                return s
206        return super(ServerLenField, self).addfield(pkt, s, val)
207
208
209class TLS_Ext_ServerName(TLS_Ext_PrettyPacketList):                 # RFC 4366
210    name = "TLS Extension - Server Name"
211    fields_desc = [ShortEnumField("type", 0, _tls_ext),
212                   MayEnd(FieldLenField("len", None, length_of="servernames",
213                                        adjust=lambda pkt, x: x + 2)),
214                   ServerLenField("servernameslen", None,
215                                  length_of="servernames"),
216                   ServerListField("servernames", [], ServerName,
217                                   length_from=lambda pkt: pkt.servernameslen)]
218
219
220class TLS_Ext_EncryptedServerName(TLS_Ext_PrettyPacketList):
221    name = "TLS Extension - Encrypted Server Name"
222    fields_desc = [ShortEnumField("type", 0xffce, _tls_ext),
223                   MayEnd(ShortField("len", None)),
224                   EnumField("cipher", None, _tls_cipher_suites),
225                   ShortEnumField("key_exchange_group", None,
226                                  _tls_named_groups),
227                   FieldLenField("key_exchange_len", None,
228                                 length_of="key_exchange", fmt="H"),
229                   XStrLenField("key_exchange", "",
230                                length_from=lambda pkt: pkt.key_exchange_len),
231                   FieldLenField("record_digest_len",
232                                 None, length_of="record_digest"),
233                   XStrLenField("record_digest", "",
234                                length_from=lambda pkt: pkt.record_digest_len),
235                   FieldLenField("encrypted_sni_len", None,
236                                 length_of="encrypted_sni", fmt="H"),
237                   XStrLenField("encrypted_sni", "",
238                                length_from=lambda pkt: pkt.encrypted_sni_len)]
239
240
241class TLS_Ext_MaxFragLen(TLS_Ext_Unknown):                          # RFC 4366
242    name = "TLS Extension - Max Fragment Length"
243    fields_desc = [ShortEnumField("type", 1, _tls_ext),
244                   MayEnd(ShortField("len", None)),
245                   ByteEnumField("maxfraglen", 4, {1: "2^9",
246                                                   2: "2^10",
247                                                   3: "2^11",
248                                                   4: "2^12"})]
249
250
251class TLS_Ext_ClientCertURL(TLS_Ext_Unknown):                       # RFC 4366
252    name = "TLS Extension - Client Certificate URL"
253    fields_desc = [ShortEnumField("type", 2, _tls_ext),
254                   MayEnd(ShortField("len", None))]
255
256
257_tls_trusted_authority_types = {0: "pre_agreed",
258                                1: "key_sha1_hash",
259                                2: "x509_name",
260                                3: "cert_sha1_hash"}
261
262
263class TAPreAgreed(Packet):
264    name = "Trusted authority - pre_agreed"
265    fields_desc = [ByteEnumField("idtype", 0, _tls_trusted_authority_types)]
266
267    def guess_payload_class(self, p):
268        return Padding
269
270
271class TAKeySHA1Hash(Packet):
272    name = "Trusted authority - key_sha1_hash"
273    fields_desc = [ByteEnumField("idtype", 1, _tls_trusted_authority_types),
274                   StrFixedLenField("id", None, 20)]
275
276    def guess_payload_class(self, p):
277        return Padding
278
279
280class TAX509Name(Packet):
281    """
282    XXX Section 3.4 of RFC 4366. Implement a more specific DNField
283    rather than current StrLenField.
284    """
285    name = "Trusted authority - x509_name"
286    fields_desc = [ByteEnumField("idtype", 2, _tls_trusted_authority_types),
287                   FieldLenField("dnlen", None, length_of="dn"),
288                   StrLenField("dn", "", length_from=lambda pkt: pkt.dnlen)]
289
290    def guess_payload_class(self, p):
291        return Padding
292
293
294class TACertSHA1Hash(Packet):
295    name = "Trusted authority - cert_sha1_hash"
296    fields_desc = [ByteEnumField("idtype", 3, _tls_trusted_authority_types),
297                   StrFixedLenField("id", None, 20)]
298
299    def guess_payload_class(self, p):
300        return Padding
301
302
303_tls_trusted_authority_cls = {0: TAPreAgreed,
304                              1: TAKeySHA1Hash,
305                              2: TAX509Name,
306                              3: TACertSHA1Hash}
307
308
309class _TAListField(PacketListField):
310    """
311    Specific version that selects the right Trusted Authority (previous TA*)
312    class to be used for dissection based on idtype.
313    """
314
315    def m2i(self, pkt, m):
316        idtype = ord(m[0])
317        cls = self.cls
318        if idtype in _tls_trusted_authority_cls:
319            cls = _tls_trusted_authority_cls[idtype]
320        return cls(m)
321
322
323class TLS_Ext_TrustedCAInd(TLS_Ext_Unknown):                        # RFC 4366
324    name = "TLS Extension - Trusted CA Indication"
325    fields_desc = [ShortEnumField("type", 3, _tls_ext),
326                   MayEnd(ShortField("len", None)),
327                   FieldLenField("talen", None, length_of="ta"),
328                   _TAListField("ta", [], Raw,
329                                length_from=lambda pkt: pkt.talen)]
330
331
332class TLS_Ext_TruncatedHMAC(TLS_Ext_Unknown):                       # RFC 4366
333    name = "TLS Extension - Truncated HMAC"
334    fields_desc = [ShortEnumField("type", 4, _tls_ext),
335                   MayEnd(ShortField("len", None))]
336
337
338class ResponderID(Packet):
339    name = "Responder ID structure"
340    fields_desc = [FieldLenField("respidlen", None, length_of="respid"),
341                   StrLenField("respid", "",
342                               length_from=lambda pkt: pkt.respidlen)]
343
344    def guess_payload_class(self, p):
345        return Padding
346
347
348class OCSPStatusRequest(Packet):
349    """
350    This is the structure defined in RFC 6066, not in RFC 6960!
351    """
352    name = "OCSPStatusRequest structure"
353    fields_desc = [FieldLenField("respidlen", None, length_of="respid"),
354                   PacketListField("respid", [], ResponderID,
355                                   length_from=lambda pkt: pkt.respidlen),
356                   FieldLenField("reqextlen", None, length_of="reqext"),
357                   PacketField("reqext", "", X509_Extensions)]
358
359    def guess_payload_class(self, p):
360        return Padding
361
362
363_cert_status_type = {1: "ocsp"}
364_cert_status_req_cls = {1: OCSPStatusRequest}
365
366
367class _StatusReqField(PacketListField):
368    def m2i(self, pkt, m):
369        idtype = pkt.stype
370        cls = self.cls
371        if idtype in _cert_status_req_cls:
372            cls = _cert_status_req_cls[idtype]
373        return cls(m)
374
375
376class TLS_Ext_CSR(TLS_Ext_Unknown):                                 # RFC 4366
377    name = "TLS Extension - Certificate Status Request"
378    fields_desc = [ShortEnumField("type", 5, _tls_ext),
379                   MayEnd(ShortField("len", None)),
380                   ByteEnumField("stype", None, _cert_status_type),
381                   _StatusReqField("req", [], Raw,
382                                   length_from=lambda pkt: pkt.len - 1)]
383
384
385class TLS_Ext_UserMapping(TLS_Ext_Unknown):                         # RFC 4681
386    name = "TLS Extension - User Mapping"
387    fields_desc = [ShortEnumField("type", 6, _tls_ext),
388                   MayEnd(ShortField("len", None)),
389                   FieldLenField("umlen", None, fmt="B", length_of="um"),
390                   FieldListField("um", [],
391                                  ByteField("umtype", 0),
392                                  length_from=lambda pkt: pkt.umlen)]
393
394
395class TLS_Ext_ClientAuthz(TLS_Ext_Unknown):                         # RFC 5878
396    """ XXX Unsupported """
397    name = "TLS Extension - Client Authz"
398    fields_desc = [ShortEnumField("type", 7, _tls_ext),
399                   MayEnd(ShortField("len", None)),
400                   ]
401
402
403class TLS_Ext_ServerAuthz(TLS_Ext_Unknown):                         # RFC 5878
404    """ XXX Unsupported """
405    name = "TLS Extension - Server Authz"
406    fields_desc = [ShortEnumField("type", 8, _tls_ext),
407                   MayEnd(ShortField("len", None)),
408                   ]
409
410
411_tls_cert_types = {0: "X.509", 1: "OpenPGP"}
412
413
414class TLS_Ext_ClientCertType(TLS_Ext_Unknown):                      # RFC 5081
415    name = "TLS Extension - Certificate Type (client version)"
416    fields_desc = [ShortEnumField("type", 9, _tls_ext),
417                   MayEnd(ShortField("len", None)),
418                   FieldLenField("ctypeslen", None, length_of="ctypes"),
419                   FieldListField("ctypes", [0, 1],
420                                  ByteEnumField("certtypes", None,
421                                                _tls_cert_types),
422                                  length_from=lambda pkt: pkt.ctypeslen)]
423
424
425class TLS_Ext_ServerCertType(TLS_Ext_Unknown):                      # RFC 5081
426    name = "TLS Extension - Certificate Type (server version)"
427    fields_desc = [ShortEnumField("type", 9, _tls_ext),
428                   MayEnd(ShortField("len", None)),
429                   ByteEnumField("ctype", None, _tls_cert_types)]
430
431
432def _TLS_Ext_CertTypeDispatcher(m, *args, **kargs):
433    """
434    We need to select the correct one on dissection. We use the length for
435    that, as 1 for client version would imply an empty list.
436    """
437    tmp_len = struct.unpack("!H", m[2:4])[0]
438    if tmp_len == 1:
439        cls = TLS_Ext_ServerCertType
440    else:
441        cls = TLS_Ext_ClientCertType
442    return cls(m, *args, **kargs)
443
444
445class TLS_Ext_SupportedGroups(TLS_Ext_Unknown):
446    """
447    This extension was known as 'Supported Elliptic Curves' before TLS 1.3
448    merged both group selection mechanisms for ECDH and FFDH.
449    """
450    name = "TLS Extension - Supported Groups"
451    fields_desc = [ShortEnumField("type", 10, _tls_ext),
452                   MayEnd(ShortField("len", None)),
453                   FieldLenField("groupslen", None, length_of="groups"),
454                   FieldListField("groups", [],
455                                  ShortEnumField("ng", None,
456                                                 _tls_named_groups),
457                                  length_from=lambda pkt: pkt.groupslen)]
458
459
460class TLS_Ext_SupportedEllipticCurves(TLS_Ext_SupportedGroups):     # RFC 4492
461    pass
462
463
464_tls_ecpoint_format = {0: "uncompressed",
465                       1: "ansiX962_compressed_prime",
466                       2: "ansiX962_compressed_char2"}
467
468
469class TLS_Ext_SupportedPointFormat(TLS_Ext_Unknown):                # RFC 4492
470    name = "TLS Extension - Supported Point Format"
471    fields_desc = [ShortEnumField("type", 11, _tls_ext),
472                   MayEnd(ShortField("len", None)),
473                   FieldLenField("ecpllen", None, fmt="B", length_of="ecpl"),
474                   FieldListField("ecpl", [0],
475                                  ByteEnumField("nc", None,
476                                                _tls_ecpoint_format),
477                                  length_from=lambda pkt: pkt.ecpllen)]
478
479
480class TLS_Ext_SignatureAlgorithms(TLS_Ext_Unknown):                 # RFC 5246
481    name = "TLS Extension - Signature Algorithms"
482    fields_desc = [ShortEnumField("type", 13, _tls_ext),
483                   MayEnd(ShortField("len", None)),
484                   SigAndHashAlgsLenField("sig_algs_len", None,
485                                          length_of="sig_algs"),
486                   SigAndHashAlgsField("sig_algs", [],
487                                       EnumField("hash_sig", None,
488                                                 _tls_hash_sig),
489                                       length_from=lambda pkt: pkt.sig_algs_len)]  # noqa: E501
490
491
492class TLS_Ext_Heartbeat(TLS_Ext_Unknown):                           # RFC 6520
493    name = "TLS Extension - Heartbeat"
494    fields_desc = [ShortEnumField("type", 0x0f, _tls_ext),
495                   MayEnd(ShortField("len", None)),
496                   ByteEnumField("heartbeat_mode", 2,
497                                 {1: "peer_allowed_to_send",
498                                  2: "peer_not_allowed_to_send"})]
499
500
501class ProtocolName(Packet):
502    name = "Protocol Name"
503    fields_desc = [FieldLenField("len", None, fmt='B', length_of="protocol"),
504                   StrLenField("protocol", "",
505                               length_from=lambda pkt: pkt.len)]
506
507    def guess_payload_class(self, p):
508        return Padding
509
510
511class ProtocolListField(PacketListField):
512    def i2repr(self, pkt, x):
513        res = [p.protocol for p in x]
514        return "[%s]" % ", ".join(repr(x) for x in res)
515
516
517class TLS_Ext_ALPN(TLS_Ext_PrettyPacketList):                       # RFC 7301
518    name = "TLS Extension - Application Layer Protocol Negotiation"
519    fields_desc = [ShortEnumField("type", 0x10, _tls_ext),
520                   MayEnd(ShortField("len", None)),
521                   FieldLenField("protocolslen", None, length_of="protocols"),
522                   ProtocolListField("protocols", [], ProtocolName,
523                                     length_from=lambda pkt:pkt.protocolslen)]
524
525
526class TLS_Ext_Padding(TLS_Ext_Unknown):                             # RFC 7685
527    name = "TLS Extension - Padding"
528    fields_desc = [ShortEnumField("type", 0x15, _tls_ext),
529                   FieldLenField("len", None, length_of="padding"),
530                   StrLenField("padding", "",
531                               length_from=lambda pkt: pkt.len)]
532
533
534class TLS_Ext_EncryptThenMAC(TLS_Ext_Unknown):                      # RFC 7366
535    name = "TLS Extension - Encrypt-then-MAC"
536    fields_desc = [ShortEnumField("type", 0x16, _tls_ext),
537                   MayEnd(ShortField("len", None))]
538
539
540class TLS_Ext_ExtendedMasterSecret(TLS_Ext_Unknown):                # RFC 7627
541    name = "TLS Extension - Extended Master Secret"
542    fields_desc = [ShortEnumField("type", 0x17, _tls_ext),
543                   MayEnd(ShortField("len", None))]
544
545
546class TLS_Ext_SessionTicket(TLS_Ext_Unknown):                       # RFC 5077
547    """
548    RFC 5077 updates RFC 4507 according to most implementations, which do not
549    use another (useless) 'ticketlen' field after the global 'len' field.
550    """
551    name = "TLS Extension - Session Ticket"
552    fields_desc = [ShortEnumField("type", 0x23, _tls_ext),
553                   FieldLenField("len", None, length_of="ticket"),
554                   StrLenField("ticket", "",
555                               length_from=lambda pkt: pkt.len)]
556
557
558class TLS_Ext_KeyShare(TLS_Ext_Unknown):
559    name = "TLS Extension - Key Share (dummy class)"
560    fields_desc = [ShortEnumField("type", 0x33, _tls_ext),
561                   MayEnd(ShortField("len", None))]
562
563
564class TLS_Ext_PreSharedKey(TLS_Ext_Unknown):
565    name = "TLS Extension - Pre Shared Key (dummy class)"
566    fields_desc = [ShortEnumField("type", 0x29, _tls_ext),
567                   MayEnd(ShortField("len", None))]
568
569
570class TLS_Ext_EarlyDataIndication(TLS_Ext_Unknown):
571    name = "TLS Extension - Early Data"
572    fields_desc = [ShortEnumField("type", 0x2a, _tls_ext),
573                   MayEnd(ShortField("len", None))]
574
575
576class TLS_Ext_EarlyDataIndicationTicket(TLS_Ext_Unknown):
577    name = "TLS Extension - Ticket Early Data Info"
578    fields_desc = [ShortEnumField("type", 0x2a, _tls_ext),
579                   MayEnd(ShortField("len", None)),
580                   IntField("max_early_data_size", 0)]
581
582
583_tls_ext_early_data_cls = {1: TLS_Ext_EarlyDataIndication,
584                           4: TLS_Ext_EarlyDataIndicationTicket,
585                           8: TLS_Ext_EarlyDataIndication}
586
587
588class TLS_Ext_SupportedVersions(TLS_Ext_Unknown):
589    name = "TLS Extension - Supported Versions (dummy class)"
590    fields_desc = [ShortEnumField("type", 0x2b, _tls_ext),
591                   MayEnd(ShortField("len", None))]
592
593
594class TLS_Ext_SupportedVersion_CH(TLS_Ext_Unknown):
595    name = "TLS Extension - Supported Versions (for ClientHello)"
596    fields_desc = [ShortEnumField("type", 0x2b, _tls_ext),
597                   MayEnd(ShortField("len", None)),
598                   FieldLenField("versionslen", None, fmt='B',
599                                 length_of="versions"),
600                   FieldListField("versions", [],
601                                  ShortEnumField("version", None,
602                                                 _tls_version),
603                                  length_from=lambda pkt: pkt.versionslen)]
604
605
606class TLS_Ext_SupportedVersion_SH(TLS_Ext_Unknown):
607    name = "TLS Extension - Supported Versions (for ServerHello)"
608    fields_desc = [ShortEnumField("type", 0x2b, _tls_ext),
609                   MayEnd(ShortField("len", None)),
610                   ShortEnumField("version", None, _tls_version)]
611
612
613_tls_ext_supported_version_cls = {1: TLS_Ext_SupportedVersion_CH,
614                                  2: TLS_Ext_SupportedVersion_SH}
615
616
617class TLS_Ext_Cookie(TLS_Ext_Unknown):
618    name = "TLS Extension - Cookie"
619    fields_desc = [ShortEnumField("type", 0x2c, _tls_ext),
620                   MayEnd(ShortField("len", None)),
621                   FieldLenField("cookielen", None, length_of="cookie"),
622                   XStrLenField("cookie", "",
623                                length_from=lambda pkt: pkt.cookielen)]
624
625    def build(self):
626        fval = self.getfieldval("cookie")
627        if fval is None or fval == b"":
628            self.cookie = os.urandom(32)
629        return TLS_Ext_Unknown.build(self)
630
631
632_tls_psk_kx_modes = {0: "psk_ke", 1: "psk_dhe_ke"}
633
634
635class TLS_Ext_PSKKeyExchangeModes(TLS_Ext_Unknown):
636    name = "TLS Extension - PSK Key Exchange Modes"
637    fields_desc = [ShortEnumField("type", 0x2d, _tls_ext),
638                   MayEnd(ShortField("len", None)),
639                   FieldLenField("kxmodeslen", None, fmt='B',
640                                 length_of="kxmodes"),
641                   FieldListField("kxmodes", [],
642                                  ByteEnumField("kxmode", None,
643                                                _tls_psk_kx_modes),
644                                  length_from=lambda pkt: pkt.kxmodeslen)]
645
646
647class TLS_Ext_TicketEarlyDataInfo(TLS_Ext_Unknown):
648    name = "TLS Extension - Ticket Early Data Info"
649    fields_desc = [ShortEnumField("type", 0x2e, _tls_ext),
650                   MayEnd(ShortField("len", None)),
651                   IntField("max_early_data_size", 0)]
652
653
654class TLS_Ext_NPN(TLS_Ext_PrettyPacketList):
655    """
656    Defined in RFC-draft-agl-tls-nextprotoneg-03. Deprecated in favour of ALPN.
657    """
658    name = "TLS Extension - Next Protocol Negotiation"
659    fields_desc = [ShortEnumField("type", 0x3374, _tls_ext),
660                   FieldLenField("len", None, length_of="protocols"),
661                   ProtocolListField("protocols", [], ProtocolName,
662                                     length_from=lambda pkt:pkt.len)]
663
664
665class TLS_Ext_PostHandshakeAuth(TLS_Ext_Unknown):                   # RFC 8446
666    name = "TLS Extension - Post Handshake Auth"
667    fields_desc = [ShortEnumField("type", 0x31, _tls_ext),
668                   MayEnd(ShortField("len", None))]
669
670
671class TLS_Ext_SignatureAlgorithmsCert(TLS_Ext_Unknown):    # RFC 8446
672    name = "TLS Extension - Signature Algorithms Cert"
673    fields_desc = [ShortEnumField("type", 0x32, _tls_ext),
674                   MayEnd(ShortField("len", None)),
675                   SigAndHashAlgsLenField("sig_algs_len", None,
676                                          length_of="sig_algs"),
677                   SigAndHashAlgsField("sig_algs", [],
678                                       EnumField("hash_sig", None,
679                                                 _tls_hash_sig),
680                                       length_from=lambda pkt: pkt.sig_algs_len)]  # noqa: E501
681
682
683class TLS_Ext_RenegotiationInfo(TLS_Ext_Unknown):                   # RFC 5746
684    name = "TLS Extension - Renegotiation Indication"
685    fields_desc = [ShortEnumField("type", 0xff01, _tls_ext),
686                   MayEnd(ShortField("len", None)),
687                   FieldLenField("reneg_conn_len", None, fmt='B',
688                                 length_of="renegotiated_connection"),
689                   StrLenField("renegotiated_connection", "",
690                               length_from=lambda pkt: pkt.reneg_conn_len)]
691
692
693class TLS_Ext_RecordSizeLimit(TLS_Ext_Unknown):  # RFC 8449
694    name = "TLS Extension - Record Size Limit"
695    fields_desc = [ShortEnumField("type", 0x1c, _tls_ext),
696                   MayEnd(ShortField("len", None)),
697                   ShortField("record_size_limit", None)]
698
699
700_tls_ext_cls = {0: TLS_Ext_ServerName,
701                1: TLS_Ext_MaxFragLen,
702                2: TLS_Ext_ClientCertURL,
703                3: TLS_Ext_TrustedCAInd,
704                4: TLS_Ext_TruncatedHMAC,
705                5: TLS_Ext_CSR,
706                6: TLS_Ext_UserMapping,
707                7: TLS_Ext_ClientAuthz,
708                8: TLS_Ext_ServerAuthz,
709                9: _TLS_Ext_CertTypeDispatcher,
710                # 10: TLS_Ext_SupportedEllipticCurves,
711                10: TLS_Ext_SupportedGroups,
712                11: TLS_Ext_SupportedPointFormat,
713                13: TLS_Ext_SignatureAlgorithms,
714                0x0f: TLS_Ext_Heartbeat,
715                0x10: TLS_Ext_ALPN,
716                0x15: TLS_Ext_Padding,
717                0x16: TLS_Ext_EncryptThenMAC,
718                0x17: TLS_Ext_ExtendedMasterSecret,
719                0x1c: TLS_Ext_RecordSizeLimit,
720                0x23: TLS_Ext_SessionTicket,
721                # 0x28: TLS_Ext_KeyShare,
722                0x29: TLS_Ext_PreSharedKey,
723                0x2a: TLS_Ext_EarlyDataIndication,
724                0x2b: TLS_Ext_SupportedVersions,
725                0x2c: TLS_Ext_Cookie,
726                0x2d: TLS_Ext_PSKKeyExchangeModes,
727                # 0x2e: TLS_Ext_TicketEarlyDataInfo,
728                0x31: TLS_Ext_PostHandshakeAuth,
729                0x32: TLS_Ext_SignatureAlgorithmsCert,
730                0x33: TLS_Ext_KeyShare,
731                # 0x2f: TLS_Ext_CertificateAuthorities,       #XXX
732                # 0x30: TLS_Ext_OIDFilters,                   #XXX
733                0x3374: TLS_Ext_NPN,
734                0xff01: TLS_Ext_RenegotiationInfo,
735                0xffce: TLS_Ext_EncryptedServerName
736                }
737
738
739class _ExtensionsLenField(FieldLenField):
740    def getfield(self, pkt, s):
741        """
742        We try to compute a length, usually from a msglen parsed earlier.
743        If we can not find any length, we consider 'extensions_present'
744        (from RFC 5246) to be False.
745        """
746        ext = pkt.get_field(self.length_of)
747        tmp_len = ext.length_from(pkt)
748        if tmp_len is None or tmp_len < 0:
749            v = pkt.tls_session.tls_version
750            if v is None or v < 0x0304:
751                return s, None
752        return super(_ExtensionsLenField, self).getfield(pkt, s)
753
754    def addfield(self, pkt, s, i):
755        """
756        There is a hack with the _ExtensionsField.i2len. It works only because
757        we expect _ExtensionsField.i2m to return a string of the same size (if
758        not of the same value) upon successive calls (e.g. through i2len here,
759        then i2m when directly building the _ExtensionsField).
760
761        XXX A proper way to do this would be to keep the extensions built from
762        the i2len call here, instead of rebuilding them later on.
763        """
764        if i is None:
765            if self.length_of is not None:
766                fld, fval = pkt.getfield_and_val(self.length_of)
767
768                tmp = pkt.tls_session.frozen
769                pkt.tls_session.frozen = True
770                f = fld.i2len(pkt, fval)
771                pkt.tls_session.frozen = tmp
772
773                i = self.adjust(pkt, f)
774                if i == 0:  # for correct build if no ext and not explicitly 0
775                    v = pkt.tls_session.tls_version
776                    # With TLS 1.3, zero lengths are always explicit.
777                    if v is None or v < 0x0304:
778                        return s
779                    else:
780                        return s + struct.pack(self.fmt, i)
781        return s + struct.pack(self.fmt, i)
782
783
784class _ExtensionsField(StrLenField):
785    islist = 1
786    holds_packets = 1
787
788    def i2len(self, pkt, i):
789        if i is None:
790            return 0
791        return len(self.i2m(pkt, i))
792
793    def getfield(self, pkt, s):
794        tmp_len = self.length_from(pkt) or 0
795        if tmp_len <= 0:
796            return s, []
797        return s[tmp_len:], self.m2i(pkt, s[:tmp_len])
798
799    def i2m(self, pkt, i):
800        if i is None:
801            return b""
802        if isinstance(pkt, _GenericTLSSessionInheritance):
803            if not pkt.tls_session.frozen:
804                s = b""
805                for ext in i:
806                    if isinstance(ext, _GenericTLSSessionInheritance):
807                        ext.tls_session = pkt.tls_session
808                        s += ext.raw_stateful()
809                    else:
810                        s += raw(ext)
811                return s
812        return b"".join(map(raw, i))
813
814    def m2i(self, pkt, m):
815        res = []
816        while len(m) >= 4:
817            t = struct.unpack("!H", m[:2])[0]
818            tmp_len = struct.unpack("!H", m[2:4])[0]
819            cls = _tls_ext_cls.get(t, TLS_Ext_Unknown)
820            if cls is TLS_Ext_KeyShare:
821                # TLS_Ext_KeyShare can be :
822                #  - TLS_Ext_KeyShare_CH if the message is a ClientHello
823                #  - TLS_Ext_KeyShare_SH if the message is a ServerHello
824                #    and all parameters are accepted by the serveur
825                #  - TLS_Ext_KeyShare_HRR if message is a ServerHello and
826                #    the client has not provided a sufficient "key_share"
827                #    extension
828                from scapy.layers.tls.keyexchange_tls13 import (
829                    _tls_ext_keyshare_cls, _tls_ext_keyshare_hrr_cls)
830                # If SHA-256("HelloRetryRequest") == server_random,
831                # this message is a HelloRetryRequest
832                if pkt.random_bytes and \
833                        pkt.random_bytes == _tls_hello_retry_magic:
834                    cls = _tls_ext_keyshare_hrr_cls.get(pkt.msgtype, TLS_Ext_Unknown)  # noqa: E501
835                else:
836                    cls = _tls_ext_keyshare_cls.get(pkt.msgtype, TLS_Ext_Unknown)  # noqa: E501
837            elif cls is TLS_Ext_PreSharedKey:
838                from scapy.layers.tls.keyexchange_tls13 import _tls_ext_presharedkey_cls  # noqa: E501
839                cls = _tls_ext_presharedkey_cls.get(pkt.msgtype, TLS_Ext_Unknown)  # noqa: E501
840            elif cls is TLS_Ext_SupportedVersions:
841                cls = _tls_ext_supported_version_cls.get(pkt.msgtype, TLS_Ext_Unknown)  # noqa: E501
842            elif cls is TLS_Ext_EarlyDataIndication:
843                cls = _tls_ext_early_data_cls.get(pkt.msgtype, TLS_Ext_Unknown)
844            res.append(cls(m[:tmp_len + 4], tls_session=pkt.tls_session))
845            m = m[tmp_len + 4:]
846        if m:
847            res.append(conf.raw_layer(m))
848        return res
849