• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1## This file is part of Scapy
2## Copyright (C) 2017 Maxence Tury
3## This program is published under a GPLv2 license
4
5"""
6TLS handshake extensions.
7"""
8
9from __future__ import print_function
10
11from scapy.fields import *
12from scapy.packet import Packet, Raw, Padding
13from scapy.layers.x509 import X509_Extensions
14from scapy.layers.tls.basefields import _tls_version
15from scapy.layers.tls.keyexchange import (SigAndHashAlgsLenField,
16                                          SigAndHashAlgsField, _tls_hash_sig)
17from scapy.layers.tls.session import _GenericTLSSessionInheritance
18from scapy.layers.tls.crypto.groups import _tls_named_groups
19
20
21_tls_ext = {  0: "server_name",             # RFC 4366
22              1: "max_fragment_length",     # RFC 4366
23              2: "client_certificate_url",  # RFC 4366
24              3: "trusted_ca_keys",         # RFC 4366
25              4: "truncated_hmac",          # RFC 4366
26              5: "status_request",          # RFC 4366
27              6: "user_mapping",            # RFC 4681
28              7: "client_authz",            # RFC 5878
29              8: "server_authz",            # RFC 5878
30              9: "cert_type",               # RFC 6091
31            #10: "elliptic_curves",         # RFC 4492
32             10: "supported_groups",
33             11: "ec_point_formats",        # RFC 4492
34             13: "signature_algorithms",    # RFC 5246
35             0x0f: "heartbeat",             # RFC 6520
36             0x10: "alpn",                  # RFC 7301
37             0x12: "signed_certificate_timestamp",  # RFC 6962
38             0x15: "padding",               # RFC 7685
39             0x16: "encrypt_then_mac",      # RFC 7366
40             0x17: "extended_master_secret",# RFC 7627
41             0x23: "session_ticket",        # RFC 5077
42             0x28: "key_share",
43             0x29: "pre_shared_key",
44             0x2a: "early_data",
45             0x2b: "supported_versions",
46             0x2c: "cookie",
47             0x2d: "psk_key_exchange_modes",
48             0x2e: "ticket_early_data_info",
49             0x2f: "certificate_authorities",
50             0x30: "oid_filters",
51             0x3374: "next_protocol_negotiation",
52                                            # RFC-draft-agl-tls-nextprotoneg-03
53             0xff01: "renegotiation_info"   # RFC 5746
54             }
55
56
57class TLS_Ext_Unknown(_GenericTLSSessionInheritance):
58    """
59    We put this here rather than in extensions.py in order to avoid
60    circular imports...
61    """
62    name = "TLS Extension - Scapy Unknown"
63    fields_desc = [ShortEnumField("type", None, _tls_ext),
64                   FieldLenField("len", None, fmt="!H", length_of="val"),
65                   StrLenField("val", "",
66                               length_from=lambda pkt: pkt.len) ]
67
68    def post_build(self, p, pay):
69        if self.len is None:
70            l = len(p) - 4
71            p = p[:2] + struct.pack("!H", l) + p[4:]
72        return p+pay
73
74
75###############################################################################
76### ClientHello/ServerHello extensions                                      ###
77###############################################################################
78
79# We provide these extensions mostly for packet manipulation purposes.
80# For now, most of them are not considered by our automaton.
81
82class TLS_Ext_PrettyPacketList(TLS_Ext_Unknown):
83    """
84    Dummy extension used for server_name/ALPN/NPN for a lighter representation:
85    the final field is showed as a 1-line list rather than as lots of packets.
86    XXX Define a new condition for packet lists in Packet._show_or_dump?
87    """
88    def _show_or_dump(self, dump=False, indent=3,
89                      lvl="", label_lvl="", first_call=True):
90        """ Reproduced from packet.py """
91        ct = AnsiColorTheme() if dump else conf.color_theme
92        s = "%s%s %s %s \n" % (label_lvl, ct.punct("###["),
93                               ct.layer_name(self.name), ct.punct("]###"))
94        for f in self.fields_desc[:-1]:
95            ncol = ct.field_name
96            vcol = ct.field_value
97            fvalue = self.getfieldval(f.name)
98            begn = "%s  %-10s%s " % (label_lvl+lvl, ncol(f.name),
99                                     ct.punct("="),)
100            reprval = f.i2repr(self,fvalue)
101            if isinstance(reprval, str):
102                reprval = reprval.replace("\n", "\n"+" "*(len(label_lvl)
103                                                          +len(lvl)
104                                                          +len(f.name)
105                                                          +4))
106            s += "%s%s\n" % (begn,vcol(reprval))
107        f = self.fields_desc[-1]
108        ncol = ct.field_name
109        vcol = ct.field_value
110        fvalue = self.getfieldval(f.name)
111        begn = "%s  %-10s%s " % (label_lvl+lvl, ncol(f.name), ct.punct("="),)
112        reprval = f.i2repr(self,fvalue)
113        if isinstance(reprval, str):
114            reprval = reprval.replace("\n", "\n"+" "*(len(label_lvl)
115                                                      +len(lvl)
116                                                      +len(f.name)
117                                                      +4))
118        s += "%s%s\n" % (begn,vcol(reprval))
119        if self.payload:
120            s += self.payload._show_or_dump(dump=dump, indent=indent,
121                                lvl=lvl+(" "*indent*self.show_indent),
122                                label_lvl=label_lvl, first_call=False)
123
124        if first_call and not dump:
125            print(s)
126        else:
127            return s
128
129
130_tls_server_name_types = { 0: "host_name" }
131
132class ServerName(Packet):
133    name = "HostName"
134    fields_desc = [ ByteEnumField("nametype", 0, _tls_server_name_types),
135                    FieldLenField("namelen", None, length_of="servername"),
136                    StrLenField("servername", "",
137                                length_from=lambda pkt: pkt.namelen) ]
138    def guess_payload_class(self, p):
139        return Padding
140
141class ServerListField(PacketListField):
142    def i2repr(self, pkt, x):
143        res = [p.servername for p in x]
144        return "[%s]" % b", ".join(res)
145
146class ServerLenField(FieldLenField):
147    """
148    There is no length when there are no servernames (as in a ServerHello).
149    """
150    def addfield(self, pkt, s, val):
151        if not val:
152            if not pkt.servernames:
153                return s
154        return super(ServerLenField, self).addfield(pkt, s, val)
155
156class TLS_Ext_ServerName(TLS_Ext_PrettyPacketList):                 # RFC 4366
157    name = "TLS Extension - Server Name"
158    fields_desc = [ShortEnumField("type", 0, _tls_ext),
159                   FieldLenField("len", None, length_of="servernames",
160                                 adjust=lambda pkt,x: x+2),
161                   ServerLenField("servernameslen", None,
162                                 length_of="servernames"),
163                   ServerListField("servernames", [], ServerName,
164                                   length_from=lambda pkt: pkt.servernameslen)]
165
166
167class TLS_Ext_MaxFragLen(TLS_Ext_Unknown):                          # RFC 4366
168    name = "TLS Extension - Max Fragment Length"
169    fields_desc = [ShortEnumField("type", 1, _tls_ext),
170                   ShortField("len", None),
171                   ByteEnumField("maxfraglen", 4, { 1: "2^9",
172                                                    2: "2^10",
173                                                    3: "2^11",
174                                                    4: "2^12" }) ]
175
176
177class TLS_Ext_ClientCertURL(TLS_Ext_Unknown):                       # RFC 4366
178    name = "TLS Extension - Client Certificate URL"
179    fields_desc = [ShortEnumField("type", 2, _tls_ext),
180                   ShortField("len", None) ]
181
182
183_tls_trusted_authority_types = {0: "pre_agreed",
184                                1: "key_sha1_hash",
185                                2: "x509_name",
186                                3: "cert_sha1_hash" }
187
188class TAPreAgreed(Packet):
189    name = "Trusted authority - pre_agreed"
190    fields_desc = [ ByteEnumField("idtype", 0, _tls_trusted_authority_types) ]
191    def guess_payload_class(self, p):
192        return Padding
193
194class TAKeySHA1Hash(Packet):
195    name = "Trusted authority - key_sha1_hash"
196    fields_desc = [ ByteEnumField("idtype", 1, _tls_trusted_authority_types),
197                    StrFixedLenField("id", None, 20) ]
198    def guess_payload_class(self, p):
199        return Padding
200
201class TAX509Name(Packet):
202    """
203    XXX Section 3.4 of RFC 4366. Implement a more specific DNField
204    rather than current StrLenField.
205    """
206    name = "Trusted authority - x509_name"
207    fields_desc = [ ByteEnumField("idtype", 2, _tls_trusted_authority_types),
208                    FieldLenField("dnlen", None, length_of="dn"),
209                    StrLenField("dn", "", length_from=lambda pkt: pkt.dnlen) ]
210    def guess_payload_class(self, p):
211        return Padding
212
213class TACertSHA1Hash(Packet):
214    name = "Trusted authority - cert_sha1_hash"
215    fields_desc = [ ByteEnumField("idtype", 3, _tls_trusted_authority_types),
216                    StrFixedLenField("id", None, 20) ]
217    def guess_payload_class(self, p):
218        return Padding
219
220_tls_trusted_authority_cls = {0: TAPreAgreed,
221                              1: TAKeySHA1Hash,
222                              2: TAX509Name,
223                              3: TACertSHA1Hash }
224
225class _TAListField(PacketListField):
226    """
227    Specific version that selects the right Trusted Authority (previous TA*)
228    class to be used for dissection based on idtype.
229    """
230    def m2i(self, pkt, m):
231        idtype = ord(m[0])
232        cls = self.cls
233        if idtype in _tls_trusted_authority_cls:
234            cls = _tls_trusted_authority_cls[idtype]
235        return cls(m)
236
237class TLS_Ext_TrustedCAInd(TLS_Ext_Unknown):                        # RFC 4366
238    name = "TLS Extension - Trusted CA Indication"
239    fields_desc = [ShortEnumField("type", 3, _tls_ext),
240                   ShortField("len", None),
241                   FieldLenField("talen", None, length_of="ta"),
242                   _TAListField("ta", [], Raw,
243                                length_from=lambda pkt: pkt.talen) ]
244
245
246class TLS_Ext_TruncatedHMAC(TLS_Ext_Unknown):                       # RFC 4366
247    name = "TLS Extension - Truncated HMAC"
248    fields_desc = [ShortEnumField("type", 4, _tls_ext),
249                   ShortField("len", None) ]
250
251
252class ResponderID(Packet):
253    name = "Responder ID structure"
254    fields_desc = [ FieldLenField("respidlen", None, length_of="respid"),
255                    StrLenField("respid", "",
256                                length_from=lambda pkt: pkt.respidlen)]
257    def guess_payload_class(self, p):
258        return Padding
259
260class OCSPStatusRequest(Packet):
261    """
262    This is the structure defined in RFC 6066, not in RFC 6960!
263    """
264    name = "OCSPStatusRequest structure"
265    fields_desc = [ FieldLenField("respidlen", None, length_of="respid"),
266                    PacketListField("respid", [], ResponderID,
267                                    length_from=lambda pkt: pkt.respidlen),
268                    FieldLenField("reqextlen", None, length_of="reqext"),
269                    PacketField("reqext", "", X509_Extensions) ]
270    def guess_payload_class(self, p):
271        return Padding
272
273_cert_status_type = { 1: "ocsp" }
274_cert_status_req_cls  = { 1: OCSPStatusRequest }
275
276class _StatusReqField(PacketListField):
277    def m2i(self, pkt, m):
278        idtype = pkt.stype
279        cls = self.cls
280        if idtype in _cert_status_req_cls:
281            cls = _cert_status_req_cls[idtype]
282        return cls(m)
283
284class TLS_Ext_CSR(TLS_Ext_Unknown):                                 # RFC 4366
285    name = "TLS Extension - Certificate Status Request"
286    fields_desc = [ShortEnumField("type", 5, _tls_ext),
287                   ShortField("len", None),
288                   ByteEnumField("stype", None, _cert_status_type),
289                   _StatusReqField("req", [], Raw,
290                                  length_from=lambda pkt: pkt.len - 1) ]
291
292
293class TLS_Ext_UserMapping(TLS_Ext_Unknown):                         # RFC 4681
294    name = "TLS Extension - User Mapping"
295    fields_desc = [ShortEnumField("type", 6, _tls_ext),
296                   ShortField("len", None),
297                   FieldLenField("umlen", None, fmt="B", length_of="um"),
298                   FieldListField("um", [],
299                                  ByteField("umtype", 0),
300                                  length_from=lambda pkt: pkt.umlen) ]
301
302
303class TLS_Ext_ClientAuthz(TLS_Ext_Unknown):                         # RFC 5878
304    """ XXX Unsupported """
305    name = "TLS Extension - Client Authz"
306    fields_desc = [ShortEnumField("type", 7, _tls_ext),
307                   ShortField("len", None),
308                   ]
309
310class TLS_Ext_ServerAuthz(TLS_Ext_Unknown):                         # RFC 5878
311    """ XXX Unsupported """
312    name = "TLS Extension - Server Authz"
313    fields_desc = [ShortEnumField("type", 8, _tls_ext),
314                   ShortField("len", None),
315                   ]
316
317
318_tls_cert_types = { 0: "X.509", 1: "OpenPGP" }
319
320class TLS_Ext_ClientCertType(TLS_Ext_Unknown):                      # RFC 5081
321    name = "TLS Extension - Certificate Type (client version)"
322    fields_desc = [ShortEnumField("type", 9, _tls_ext),
323                   ShortField("len", None),
324                   FieldLenField("ctypeslen", None, length_of="ctypes"),
325                   FieldListField("ctypes", [0, 1],
326                                  ByteEnumField("certtypes", None,
327                                                _tls_cert_types),
328                                  length_from=lambda pkt: pkt.ctypeslen) ]
329
330class TLS_Ext_ServerCertType(TLS_Ext_Unknown):                      # RFC 5081
331    name = "TLS Extension - Certificate Type (server version)"
332    fields_desc = [ShortEnumField("type", 9, _tls_ext),
333                   ShortField("len", None),
334                   ByteEnumField("ctype", None, _tls_cert_types) ]
335
336def _TLS_Ext_CertTypeDispatcher(m, *args, **kargs):
337    """
338    We need to select the correct one on dissection. We use the length for
339    that, as 1 for client version would emply an empty list.
340    """
341    l = struct.unpack("!H", m[2:4])[0]
342    if l == 1:
343        cls = TLS_Ext_ServerCertType
344    else:
345        cls = TLS_Ext_ClientCertType
346    return cls(m, *args, **kargs)
347
348
349class TLS_Ext_SupportedGroups(TLS_Ext_Unknown):
350    """
351    This extension was known as 'Supported Elliptic Curves' before TLS 1.3
352    merged both group selection mechanisms for ECDH and FFDH.
353    """
354    name = "TLS Extension - Supported Groups"
355    fields_desc = [ShortEnumField("type", 10, _tls_ext),
356                   ShortField("len", None),
357                   FieldLenField("groupslen", None, length_of="groups"),
358                   FieldListField("groups", [],
359                                  ShortEnumField("ng", None,
360                                                 _tls_named_groups),
361                                  length_from=lambda pkt: pkt.groupslen) ]
362
363class TLS_Ext_SupportedEllipticCurves(TLS_Ext_SupportedGroups):     # RFC 4492
364    pass
365
366
367_tls_ecpoint_format = { 0: "uncompressed",
368                        1: "ansiX962_compressed_prime",
369                        2: "ansiX962_compressed_char2" }
370
371class TLS_Ext_SupportedPointFormat(TLS_Ext_Unknown):                # RFC 4492
372    name = "TLS Extension - Supported Point Format"
373    fields_desc = [ShortEnumField("type", 11, _tls_ext),
374                   ShortField("len", None),
375                   FieldLenField("ecpllen", None, fmt="B", length_of="ecpl"),
376                   FieldListField("ecpl", [0],
377                                    ByteEnumField("nc", None,
378                                                  _tls_ecpoint_format),
379                                    length_from=lambda pkt: pkt.ecpllen) ]
380
381
382class TLS_Ext_SignatureAlgorithms(TLS_Ext_Unknown):                 # RFC 5246
383    name = "TLS Extension - Signature Algorithms"
384    fields_desc = [ShortEnumField("type", 13, _tls_ext),
385                   ShortField("len", None),
386                   SigAndHashAlgsLenField("sig_algs_len", None,
387                                          length_of="sig_algs"),
388                   SigAndHashAlgsField("sig_algs", [],
389                                       EnumField("hash_sig", None,
390                                                    _tls_hash_sig),
391                                       length_from=
392                                           lambda pkt: pkt.sig_algs_len) ]
393
394
395class TLS_Ext_Heartbeat(TLS_Ext_Unknown):                           # RFC 6520
396    name = "TLS Extension - Heartbeat"
397    fields_desc = [ShortEnumField("type", 0x0f, _tls_ext),
398                   ShortField("len", None),
399                   ByteEnumField("heartbeat_mode", 2,
400                       { 1: "peer_allowed_to_send",
401                         2: "peer_not_allowed_to_send" }) ]
402
403
404class ProtocolName(Packet):
405    name = "Protocol Name"
406    fields_desc = [ FieldLenField("len", None, fmt='B', length_of="protocol"),
407                    StrLenField("protocol", "",
408                                length_from=lambda pkt: pkt.len)]
409    def guess_payload_class(self, p):
410        return Padding
411
412class ProtocolListField(PacketListField):
413    def i2repr(self, pkt, x):
414        res = [p.protocol for p in x]
415        return "[%s]" % b", ".join(res)
416
417class TLS_Ext_ALPN(TLS_Ext_PrettyPacketList):                       # RFC 7301
418    name = "TLS Extension - Application Layer Protocol Negotiation"
419    fields_desc = [ShortEnumField("type", 0x10, _tls_ext),
420                   ShortField("len", None),
421                   FieldLenField("protocolslen", None, length_of="protocols"),
422                   ProtocolListField("protocols", [], ProtocolName,
423                                     length_from=lambda pkt:pkt.protocolslen) ]
424
425
426class TLS_Ext_Padding(TLS_Ext_Unknown):                             # RFC 7685
427    name = "TLS Extension - Padding"
428    fields_desc = [ShortEnumField("type", 0x15, _tls_ext),
429                   FieldLenField("len", None, length_of="padding"),
430                   StrLenField("padding", "",
431                               length_from=lambda pkt: pkt.len) ]
432
433
434class TLS_Ext_EncryptThenMAC(TLS_Ext_Unknown):                      # RFC 7366
435    name = "TLS Extension - Encrypt-then-MAC"
436    fields_desc = [ShortEnumField("type", 0x16, _tls_ext),
437                   ShortField("len", None) ]
438
439
440class TLS_Ext_ExtendedMasterSecret(TLS_Ext_Unknown):                # RFC 7627
441    name = "TLS Extension - Extended Master Secret"
442    fields_desc = [ShortEnumField("type", 0x17, _tls_ext),
443                   ShortField("len", None) ]
444
445
446class TLS_Ext_SessionTicket(TLS_Ext_Unknown):                       # RFC 5077
447    """
448    RFC 5077 updates RFC 4507 according to most implementations, which do not
449    use another (useless) 'ticketlen' field after the global 'len' field.
450    """
451    name = "TLS Extension - Session Ticket"
452    fields_desc = [ShortEnumField("type", 0x23, _tls_ext),
453                   FieldLenField("len", None, length_of="ticket"),
454                   StrLenField("ticket", "",
455                               length_from=lambda pkt: pkt.len) ]
456
457
458class TLS_Ext_KeyShare(TLS_Ext_Unknown):
459    name = "TLS Extension - Key Share (dummy class)"
460    fields_desc = [ShortEnumField("type", 0x28, _tls_ext),
461                   ShortField("len", None) ]
462
463
464class TLS_Ext_PreSharedKey(TLS_Ext_Unknown):
465    name = "TLS Extension - Pre Shared Key (dummy class)"
466    fields_desc = [ShortEnumField("type", 0x29, _tls_ext),
467                   ShortField("len", None) ]
468
469
470class TLS_Ext_EarlyData(TLS_Ext_Unknown):
471    name = "TLS Extension - Early Data"
472    fields_desc = [ShortEnumField("type", 0x2a, _tls_ext),
473                   ShortField("len", None) ]
474
475
476class TLS_Ext_SupportedVersions(TLS_Ext_Unknown):
477    name = "TLS Extension - Supported Versions"
478    fields_desc = [ShortEnumField("type", 0x2b, _tls_ext),
479                   ShortField("len", None),
480                   FieldLenField("versionslen", None, fmt='B',
481                                 length_of="versions"),
482                   FieldListField("versions", [],
483                                  ShortEnumField("version", None,
484                                                 _tls_version),
485                                  length_from=lambda pkt: pkt.versionslen) ]
486
487
488class TLS_Ext_Cookie(TLS_Ext_Unknown):
489    name = "TLS Extension - Cookie"
490    fields_desc = [ShortEnumField("type", 0x2c, _tls_ext),
491                   ShortField("len", None),
492                   FieldLenField("cookielen", None, length_of="cookie"),
493                   XStrLenField("cookie", "",
494                                length_from=lambda pkt: pkt.cookielen) ]
495
496
497_tls_psk_kx_modes = { 0: "psk_ke", 1: "psk_dhe_ke" }
498
499class TLS_Ext_PSKKeyExchangeModes(TLS_Ext_Unknown):
500    name = "TLS Extension - PSK Key Exchange Modes"
501    fields_desc = [ShortEnumField("type", 0x2d, _tls_ext),
502                   ShortField("len", None),
503                   FieldLenField("kxmodeslen", None, fmt='B',
504                                 length_of="kxmodes"),
505                   FieldListField("kxmodes", [],
506                                  ByteEnumField("kxmode", None,
507                                                 _tls_psk_kx_modes),
508                                  length_from=lambda pkt: pkt.kxmodeslen) ]
509
510
511class TLS_Ext_TicketEarlyDataInfo(TLS_Ext_Unknown):
512    name = "TLS Extension - Ticket Early Data Info"
513    fields_desc = [ShortEnumField("type", 0x2e, _tls_ext),
514                   ShortField("len", None),
515                   IntField("max_early_data_size", 0) ]
516
517
518class TLS_Ext_NPN(TLS_Ext_PrettyPacketList):
519    """
520    Defined in RFC-draft-agl-tls-nextprotoneg-03. Deprecated in favour of ALPN.
521    """
522    name = "TLS Extension - Next Protocol Negotiation"
523    fields_desc = [ShortEnumField("type", 0x3374, _tls_ext),
524                   FieldLenField("len", None, length_of="protocols"),
525                   ProtocolListField("protocols", [], ProtocolName,
526                                     length_from=lambda pkt:pkt.len) ]
527
528
529class TLS_Ext_RenegotiationInfo(TLS_Ext_Unknown):                   # RFC 5746
530    name = "TLS Extension - Renegotiation Indication"
531    fields_desc = [ShortEnumField("type", 0xff01, _tls_ext),
532                   ShortField("len", None),
533                   FieldLenField("reneg_conn_len", None, fmt='B',
534                                 length_of="renegotiated_connection"),
535                   StrLenField("renegotiated_connection", "",
536                               length_from=lambda pkt: pkt.reneg_conn_len) ]
537
538
539_tls_ext_cls = { 0: TLS_Ext_ServerName,
540                 1: TLS_Ext_MaxFragLen,
541                 2: TLS_Ext_ClientCertURL,
542                 3: TLS_Ext_TrustedCAInd,
543                 4: TLS_Ext_TruncatedHMAC,
544                 5: TLS_Ext_CSR,
545                 6: TLS_Ext_UserMapping,
546                 7: TLS_Ext_ClientAuthz,
547                 8: TLS_Ext_ServerAuthz,
548                 9: _TLS_Ext_CertTypeDispatcher,
549               #10: TLS_Ext_SupportedEllipticCurves,
550                10: TLS_Ext_SupportedGroups,
551                11: TLS_Ext_SupportedPointFormat,
552                13: TLS_Ext_SignatureAlgorithms,
553                0x0f: TLS_Ext_Heartbeat,
554                0x10: TLS_Ext_ALPN,
555                0x15: TLS_Ext_Padding,
556                0x16: TLS_Ext_EncryptThenMAC,
557                0x17: TLS_Ext_ExtendedMasterSecret,
558                0x23: TLS_Ext_SessionTicket,
559                0x28: TLS_Ext_KeyShare,
560                0x29: TLS_Ext_PreSharedKey,
561                0x2a: TLS_Ext_EarlyData,
562                0x2b: TLS_Ext_SupportedVersions,
563                0x2c: TLS_Ext_Cookie,
564                0x2d: TLS_Ext_PSKKeyExchangeModes,
565                0x2e: TLS_Ext_TicketEarlyDataInfo,
566               #0x2f: TLS_Ext_CertificateAuthorities,       #XXX
567               #0x30: TLS_Ext_OIDFilters,                   #XXX
568                0x3374: TLS_Ext_NPN,
569                0xff01: TLS_Ext_RenegotiationInfo
570                }
571
572
573class _ExtensionsLenField(FieldLenField):
574    def getfield(self, pkt, s):
575        """
576        We try to compute a length, usually from a msglen parsed earlier.
577        If this length is 0, we consider 'selection_present' (from RFC 5246)
578        to be False. This means that there should not be any length field.
579        However, with TLS 1.3, zero lengths are always explicit.
580        """
581        ext = pkt.get_field(self.length_of)
582        l = ext.length_from(pkt)
583        if l is None or l <= 0:
584            v = pkt.tls_session.tls_version
585            if v is None or v < 0x0304:
586                return s, None
587        return super(_ExtensionsLenField, self).getfield(pkt, s)
588
589    def addfield(self, pkt, s, i):
590        """
591        There is a hack with the _ExtensionsField.i2len. It works only because
592        we expect _ExtensionsField.i2m to return a string of the same size (if
593        not of the same value) upon successive calls (e.g. through i2len here,
594        then i2m when directly building the _ExtensionsField).
595
596        XXX A proper way to do this would be to keep the extensions built from
597        the i2len call here, instead of rebuilding them later on.
598        """
599        if i is None:
600            if self.length_of is not None:
601                fld,fval = pkt.getfield_and_val(self.length_of)
602
603                tmp = pkt.tls_session.frozen
604                pkt.tls_session.frozen = True
605                f = fld.i2len(pkt, fval)
606                pkt.tls_session.frozen = tmp
607
608                i = self.adjust(pkt, f)
609                if i == 0: # for correct build if no ext and not explicitly 0
610                    return s
611        return s + struct.pack(self.fmt, i)
612
613class _ExtensionsField(StrLenField):
614    islist=1
615    holds_packets=1
616
617    def i2len(self, pkt, i):
618        if i is None:
619            return 0
620        return len(self.i2m(pkt, i))
621
622    def getfield(self, pkt, s):
623        l = self.length_from(pkt)
624        if l is None:
625            return s, []
626        return s[l:], self.m2i(pkt, s[:l])
627
628    def i2m(self, pkt, i):
629        if i is None:
630            return b""
631        if isinstance(pkt, _GenericTLSSessionInheritance):
632            if not pkt.tls_session.frozen:
633                s = b""
634                for ext in i:
635                    if isinstance(ext, _GenericTLSSessionInheritance):
636                        ext.tls_session = pkt.tls_session
637                        s += ext.raw_stateful()
638                    else:
639                        s += raw(ext)
640                return s
641        return b"".join(map(raw, i))
642
643    def m2i(self, pkt, m):
644        res = []
645        while m:
646            t = struct.unpack("!H", m[:2])[0]
647            l = struct.unpack("!H", m[2:4])[0]
648            cls = _tls_ext_cls.get(t, TLS_Ext_Unknown)
649            if cls is TLS_Ext_KeyShare:
650                from scapy.layers.tls.keyexchange_tls13 import _tls_ext_keyshare_cls
651                cls = _tls_ext_keyshare_cls.get(pkt.msgtype, TLS_Ext_Unknown)
652            elif cls is TLS_Ext_PreSharedKey:
653                from scapy.layers.tls.keyexchange_tls13 import _tls_ext_presharedkey_cls
654                cls = _tls_ext_presharedkey_cls.get(pkt.msgtype, TLS_Ext_Unknown)
655            res.append(cls(m[:l+4], tls_session=pkt.tls_session))
656            m = m[l+4:]
657        return res
658
659
660