Repository: secdev/scapy

Issue:
Add Encrypted Server Name Indication for TLS 1.3
Added ability to dissect and use [TLS ESNI](https://datatracker.ietf.org/doc/draft-ietf-tls-esni/)
fixes #2096



Discussion:

Resolving patch:
diff --git a/scapy/layers/tls/extensions.py b/scapy/layers/tls/extensions.py
--- a/scapy/layers/tls/extensions.py
+++ b/scapy/layers/tls/extensions.py
@@ -21,6 +21,7 @@
                                           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
@@ -81,7 +82,8 @@
             0x33: "key_share",
             0x3374: "next_protocol_negotiation",
             # RFC-draft-agl-tls-nextprotoneg-03
-            0xff01: "renegotiation_info"   # RFC 5746
+            0xff01: "renegotiation_info",   # RFC 5746
+            0xffce: "encrypted_server_name"
             }
 
 
@@ -202,6 +204,27 @@ class TLS_Ext_ServerName(TLS_Ext_PrettyPacketList):                 # RFC 4366
                                    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),
@@ -695,7 +718,8 @@ class TLS_Ext_RecordSizeLimit(TLS_Ext_Unknown):  # RFC 8449
                 # 0x2f: TLS_Ext_CertificateAuthorities,       #XXX
                 # 0x30: TLS_Ext_OIDFilters,                   #XXX
                 0x3374: TLS_Ext_NPN,
-                0xff01: TLS_Ext_RenegotiationInfo
+                0xff01: TLS_Ext_RenegotiationInfo,
+                0xffce: TLS_Ext_EncryptedServerName
                 }
 
 


Test patch:
diff --git a/test/tls13.uts b/test/tls13.uts
--- a/test/tls13.uts
+++ b/test/tls13.uts
@@ -619,6 +619,54 @@ m = t.inner.msg[0]
 assert(isinstance(m, TLSApplicationData))
 assert(m.data == payload)
 
+= TLS_Ext_EncryptedServerName(), dissect
+~ crypto_advanced
+
+clientHello3 = clean("""
+16030102c4010002c003034b1 40e7d15fc8db422cec056fbaf 0285d306df4eedad1bc6ea57d 5114e6bd52a20a5b9c7445955 e296b886469c974648cda0a68
+5d3c06d884e388f6475c32e03 2d0024130113031302c02bc02 fcca9cca8c02cc030c00ac009 c013c01400330039002f00350 00a0100025300170000ff0100
+0100000a000e000c001d00170 018001901000101000b000201 00002300000010000b0009086 87474702f312e310005000501 000000000033006b0069001d0
+02037adee0aacc37b08d47222 caf6a5097a800fcf8406ae118 38f6348294d2dde1200170041 048b127c905d6d487a40b8b19 c99c56aa1a8c208218c178dae
+02568547b2ce8f538a530b858 a7a2f608d66e148baa5693d03 c519b45017c63f48c5a4c1238 707bc002b0009080304030303 020301000d001800160403050
+3060308040805080604010501 060102030201002d00020101f fce016e1301001d0020912e86 b776ee552a6bb1e2c70d7b467 770b190432237cc743a93091d
+ce24623500208bc16fdcbbc7c 8756808c94f70464d68297975 f33be90e1a200633f5eb2d4c6 101249e073bff833782e57e88 2519a53ef8bde4c94a7878a2f
+8461aec57802440007c7b2dab 986d9bc79257ce00ca6a998b1 fadb0114161069d364ccebae8 dab6c88151f297daeaecfd2e1 a598a486e2efc9561298f8dd5
+f35d184f0e87768777d253e68 952b730a24b342fde10df4f8e 82afdc2f10c2481634d92015d 9d5e6a9566494735d9c079115 bdeb0cd019098d1cf847c53ef
+4aac41560cacdc7ce166399df 5b0c0af91d5be3f7d8224755a aa6046de52875f9ef9ac15372 7ce08019bc2648beb4b1418cb 4979ff7eaeedaec2b15695508
+4d5a480cb939fdc7f00e6cc6f c0f9675276a9d607686c4d779 d4bb7544fb60c7f3079afbc74 61ed67fd55a78c44d6f8d4eaf 386acc17dea11e37a09f63da3
+d059243b35f449e891255ac7b 4f631509d7060f001c0002400 1
+""")
+t = TLS(clientHello3)
+clientESNI = t.msg[0].ext[11]
+assert isinstance(clientESNI, TLS_Ext_EncryptedServerName) and clientESNI.cipher == 4865
+
+
+= TLS_Ext_EncryptedServerName(),  basic instantiation
+~ crypto_advanced
+
+esni = TLS_Ext_EncryptedServerName(key_exchange_group=29,encrypted_sni=clean("""
+ffce016e1301001d00209 12e86b776ee552a6bb1e2 c70d7b467770b19043223 7cc743a93091dce246235
+00208bc16fdcbbc7c8756 808c94f70464d68297975 f33be90e1a200633f5eb2 d4c6101249e073bff8337
+82e57e882519a53ef8bde 4c94a7878a2f8461aec57 802440007c7b2dab986d9 bc79257ce00ca6a998b1f
+adb0114161069d364cceb ae8dab6c88151f297daea ecfd2e1a598a486e2efc9 561298f8dd5f35d184f0e
+87768777d253e68952b73 0a24b342fde10df4f8e82 afdc2f10c2481634d9201 5d9d5e6a9566494735d9c
+079115bdeb0cd019098d1 cf847c53ef4aac41560ca cdc7ce166399df5b0c0af 91d5be3f7d8224755aaa6
+046de52875f9ef9ac1537 27ce08019bc2648beb4b1 418cb4979ff7eaeedaec2 b156955084d5a480cb939
+fdc7f00e6cc6fc0f96752 76a9d607686c4d779d4bb 7544fb60c7f3079afbc74 61ed67fd55a78c44d6f8d
+4eaf386acc17dea11e37a 09f63da3d059243b35f44 9e891255ac7b4f631509d 7060f
+"""))
+assert esni.key_exchange_group == 29 and esni.encrypted_sni==clean("""
+ffce016e1301001d00209 12e86b776ee552a6bb1e2 c70d7b467770b19043223 7cc743a93091dce246235
+00208bc16fdcbbc7c8756 808c94f70464d68297975 f33be90e1a200633f5eb2 d4c6101249e073bff8337
+82e57e882519a53ef8bde 4c94a7878a2f8461aec57 802440007c7b2dab986d9 bc79257ce00ca6a998b1f
+adb0114161069d364cceb ae8dab6c88151f297daea ecfd2e1a598a486e2efc9 561298f8dd5f35d184f0e
+87768777d253e68952b73 0a24b342fde10df4f8e82 afdc2f10c2481634d9201 5d9d5e6a9566494735d9c
+079115bdeb0cd019098d1 cf847c53ef4aac41560ca cdc7ce166399df5b0c0af 91d5be3f7d8224755aaa6
+046de52875f9ef9ac1537 27ce08019bc2648beb4b1 418cb4979ff7eaeedaec2 b156955084d5a480cb939
+fdc7f00e6cc6fc0f96752 76a9d607686c4d779d4bb 7544fb60c7f3079afbc74 61ed67fd55a78c44d6f8d
+4eaf386acc17dea11e37a 09f63da3d059243b35f44 9e891255ac7b4f631509d 7060f
+""")
+
 = Decrypt a TLS 1.3 session - Decrypt and parse server Application Data
 ~ crypto_advanced
 # Values from RFC8448, section 3