From d902057b142c6ff659db6c3c83dcf1f7cf0ddf0a Mon Sep 17 00:00:00 2001 From: Adam Janovsky Date: Thu, 23 Aug 2018 15:03:10 +0200 Subject: [PATCH 1/8] Added extms support to TLS --- scapy/layers/tls/crypto/prf.py | 11 +++++++++-- scapy/layers/tls/handshake.py | 27 ++++++++++++++++++++++++++- scapy/layers/tls/session.py | 9 ++++++++- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/scapy/layers/tls/crypto/prf.py b/scapy/layers/tls/crypto/prf.py index 5f7692ded6b..8896cb486ae 100644 --- a/scapy/layers/tls/crypto/prf.py +++ b/scapy/layers/tls/crypto/prf.py @@ -208,18 +208,25 @@ def __init__(self, hash_name="SHA256", tls_version=0x0303): warning("Unknown TLS version") def compute_master_secret(self, pre_master_secret, - client_random, server_random): + client_random, server_random, extms=False, handshake_hash=None): """ Return the 48-byte master_secret, computed from pre_master_secret, client_random and server_random. See RFC 5246, section 6.3. + Supports Extended Master Secret Derivation, see RFC 7627 """ seed = client_random + server_random + label = b'master secret' + + if extms is True and handshake_hash is not None: + seed = handshake_hash + label = b'extended master secret' + if self.tls_version < 0x0300: return None elif self.tls_version == 0x0300: return self.prf(pre_master_secret, seed, 48) else: - return self.prf(pre_master_secret, b"master secret", seed, 48) + return self.prf(pre_master_secret, label, seed, 48) def derive_key_block(self, master_secret, server_random, client_random, req_len): diff --git a/scapy/layers/tls/handshake.py b/scapy/layers/tls/handshake.py index 79c0650e120..168caca8cb8 100644 --- a/scapy/layers/tls/handshake.py +++ b/scapy/layers/tls/handshake.py @@ -29,7 +29,8 @@ from scapy.layers.tls.basefields import (_tls_version, _TLSVersionField, _TLSClientVersionField) from scapy.layers.tls.extensions import (_ExtensionsLenField, _ExtensionsField, - _cert_status_type, TLS_Ext_SupportedVersions) # noqa: E501 + _cert_status_type, TLS_Ext_SupportedVersions, + TLS_Ext_ExtendedMasterSecret) # noqa: E501 from scapy.layers.tls.keyexchange import (_TLSSignature, _TLSServerParamsField, _TLSSignatureField, ServerRSAParams, SigAndHashAlgsField, _tls_hash_sig, @@ -86,6 +87,7 @@ def tls_session_update(self, msg_str): """ Covers both post_build- and post_dissection- context updates. """ + self.tls_session.handshake_messages.append(msg_str) self.tls_session.handshake_messages_parsed.append(self) @@ -370,6 +372,13 @@ def tls_session_update(self, msg_str): self.random_bytes) self.tls_session.sid = self.sid + # EXTMS + if self.ext: + for e in self.ext: + if isinstance(e, TLS_Ext_ExtendedMasterSecret): + self.tls_session.extms = True + break + cs_cls = None if self.cipher: cs_val = self.cipher @@ -964,6 +973,22 @@ def build(self, *args, **kargs): self.exchkeys = cls return _TLSHandshake.build(self, *args, **kargs) + def tls_session_update(self, msg_str): + """ + Finalize the EXTMS messages and compute the hash + """ + + self.tls_session.handshake_messages.append(msg_str) + self.tls_session.handshake_messages_parsed.append(self) + + if self.tls_session.extms: + hash_object = self.tls_session.pwcs.hash + to_hash = b''.join(self.tls_session.handshake_messages) + self.tls_session.session_hash = hash_object.digest(to_hash) + + + + ############################################################################### # Finished # diff --git a/scapy/layers/tls/session.py b/scapy/layers/tls/session.py index 97a1c7efd98..1713f4b406f 100644 --- a/scapy/layers/tls/session.py +++ b/scapy/layers/tls/session.py @@ -448,6 +448,10 @@ def __init__(self, self.handshake_messages = [] self.handshake_messages_parsed = [] + # Flag, whether we derive the secret as Extended MS or not + self.extms = False + self.session_hash = None + # All exchanged TLS packets. # XXX no support for now # self.exchanged_pkts = [] @@ -522,9 +526,12 @@ def compute_master_secret(self): if self.server_random is None: warning("Missing server_random while computing master_secret!") + ms = self.pwcs.prf.compute_master_secret(self.pre_master_secret, self.client_random, - self.server_random) + self.server_random, + self.extms, + self.session_hash) self.master_secret = ms if conf.debug_tls: log_runtime.debug("TLS: master secret: %s", repr_hex(ms)) From 392d16596255aba7a0d76e75386305c8b42f1bea Mon Sep 17 00:00:00 2001 From: Adam Janovsky Date: Thu, 23 Aug 2018 15:48:41 +0200 Subject: [PATCH 2/8] minor fix --- scapy/layers/tls/session.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scapy/layers/tls/session.py b/scapy/layers/tls/session.py index 1713f4b406f..d64536b3211 100644 --- a/scapy/layers/tls/session.py +++ b/scapy/layers/tls/session.py @@ -525,7 +525,8 @@ def compute_master_secret(self): warning("Missing client_random while computing master_secret!") if self.server_random is None: warning("Missing server_random while computing master_secret!") - + if self.extms and self.session_hash is None: + warning("Missing session hash while computing master secret!") ms = self.pwcs.prf.compute_master_secret(self.pre_master_secret, self.client_random, From 83fcc0dcabbdfa0d71945a8ef7038a3780e5d74e Mon Sep 17 00:00:00 2001 From: gpotter2 Date: Sun, 18 Nov 2018 01:38:29 +0100 Subject: [PATCH 3/8] TLS 1.3: mashup (WIP) --- scapy/layers/inet.py | 4 +- scapy/layers/tls/automaton_cli.py | 4 +- scapy/layers/tls/basefields.py | 13 +- scapy/layers/tls/crypto/cipher_aead.py | 6 +- scapy/layers/tls/crypto/prf.py | 3 +- scapy/layers/tls/extensions.py | 37 ++- scapy/layers/tls/handshake.py | 195 ++++++----- scapy/layers/tls/keyexchange_tls13.py | 8 +- scapy/layers/tls/record.py | 18 +- scapy/layers/tls/record_tls13.py | 2 +- test/tls13.uts | 438 +++++++++++++++---------- tls-13-handshake.pcap | Bin 0 -> 8525 bytes 12 files changed, 412 insertions(+), 316 deletions(-) create mode 100644 tls-13-handshake.pcap diff --git a/scapy/layers/inet.py b/scapy/layers/inet.py index aa5d0b41cea..a7f93c50768 100644 --- a/scapy/layers/inet.py +++ b/scapy/layers/inet.py @@ -466,7 +466,9 @@ class IP(Packet, IPTools): # IPField("src", "127.0.0.1"), Emph(SourceIPField("src", "dst")), Emph(DestIPField("dst", "127.0.0.1")), - PacketListField("options", [], IPOption, length_from=lambda p:p.ihl * 4 - 20)] # noqa: E501 + PacketListField("options", [], IPOption, length_from=( + lambda p: max(0, p.ihl * 4 - 20))) + ] def post_build(self, p, pay): ihl = self.ihl diff --git a/scapy/layers/tls/automaton_cli.py b/scapy/layers/tls/automaton_cli.py index 765ee5e3bd9..aec329a9c4f 100644 --- a/scapy/layers/tls/automaton_cli.py +++ b/scapy/layers/tls/automaton_cli.py @@ -31,7 +31,7 @@ from scapy.layers.tls.handshake import TLSCertificate, TLSCertificateRequest, \ TLSCertificateVerify, TLSClientHello, TLSClientKeyExchange, \ TLSEncryptedExtensions, TLSFinished, TLSServerHello, TLSServerHelloDone, \ - TLSServerKeyExchange, TLS13Certificate, TLS13ServerHello + TLSServerKeyExchange, TLS13Certificate from scapy.layers.tls.handshake_sslv2 import SSLv2ClientHello, \ SSLv2ServerHello, SSLv2ClientMasterKey, SSLv2ServerVerify, \ SSLv2ClientFinished, SSLv2ServerFinished, SSLv2ClientCertificate, \ @@ -856,7 +856,7 @@ def TLS13_WAITING_SERVERHELLO(self): @ATMT.condition(TLS13_WAITING_SERVERHELLO) def tls13_should_handle_ServerHello(self): - self.raise_on_packet(TLS13ServerHello, + self.raise_on_packet(TLSServerHello, self.TLS13_WAITING_ENCRYPTEDEXTENSIONS) @ATMT.state() diff --git a/scapy/layers/tls/basefields.py b/scapy/layers/tls/basefields.py index 752b562ec1f..6c4968a975a 100644 --- a/scapy/layers/tls/basefields.py +++ b/scapy/layers/tls/basefields.py @@ -18,6 +18,9 @@ 22: "handshake", 23: "application_data"} +# Types that will redirect to a TLS13 record if available +_tls_type_13 = [23] + _tls_version = {0x0002: "SSLv2", 0x0200: "SSLv2", 0x0300: "SSLv3", @@ -72,27 +75,27 @@ def i2m(self, pkt, x): class _TLSVersionField(ShortEnumField): """ We use the tls_version if it has been defined, else the advertised version. - Also, the legacy 0x0301 is used for TLS 1.3 packets. + Also, the legacy 0x0303 is used for TLS 1.3 packets. """ def i2h(self, pkt, x): if x is None: v = pkt.tls_session.tls_version if v: - return _tls13_version_filter(v, 0x0301) + return _tls13_version_filter(v, 0x0303) else: adv_v = pkt.tls_session.advertised_tls_version - return _tls13_version_filter(adv_v, 0x0301) + return _tls13_version_filter(adv_v, 0x0303) return x def i2m(self, pkt, x): if x is None: v = pkt.tls_session.tls_version if v: - return _tls13_version_filter(v, 0x0301) + return _tls13_version_filter(v, 0x0303) else: adv_v = pkt.tls_session.advertised_tls_version - return _tls13_version_filter(adv_v, 0x0301) + return _tls13_version_filter(adv_v, 0x0303) return x diff --git a/scapy/layers/tls/crypto/cipher_aead.py b/scapy/layers/tls/crypto/cipher_aead.py index 99b77712e0c..49919ab65c3 100644 --- a/scapy/layers/tls/crypto/cipher_aead.py +++ b/scapy/layers/tls/crypto/cipher_aead.py @@ -206,7 +206,7 @@ def auth_decrypt(self, A, C, seq_num=None, add_length=True): P = self._cipher.decrypt(self._get_nonce(), C + mac, A) except InvalidTag: raise AEADTagError(nonce_explicit_str, - "", + b"", mac) return nonce_explicit_str, P, mac @@ -366,7 +366,7 @@ def auth_decrypt(self, A, C, seq_num): A += struct.pack("!H", len(C)) P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A) # noqa: E501 except InvalidTag: - raise AEADTagError("", mac) + raise AEADTagError(b"", mac) return P, mac def snapshot(self): @@ -400,8 +400,8 @@ class Cipher_AES_128_GCM_TLS13(_AEADCipher_TLS13): pc_cls = algorithms.AES pc_cls_mode = modes.GCM key_len = 16 - fixed_iv_len = 12 tag_len = 16 + fixed_iv_len = 12 class Cipher_AES_256_GCM_TLS13(Cipher_AES_128_GCM_TLS13): key_len = 32 diff --git a/scapy/layers/tls/crypto/prf.py b/scapy/layers/tls/crypto/prf.py index 8896cb486ae..6c95f5329af 100644 --- a/scapy/layers/tls/crypto/prf.py +++ b/scapy/layers/tls/crypto/prf.py @@ -208,7 +208,8 @@ def __init__(self, hash_name="SHA256", tls_version=0x0303): warning("Unknown TLS version") def compute_master_secret(self, pre_master_secret, - client_random, server_random, extms=False, handshake_hash=None): + client_random, server_random, + extms=False, handshake_hash=None): """ Return the 48-byte master_secret, computed from pre_master_secret, client_random and server_random. See RFC 5246, section 6.3. diff --git a/scapy/layers/tls/extensions.py b/scapy/layers/tls/extensions.py index ffec02aa1ea..def312a8cf2 100644 --- a/scapy/layers/tls/extensions.py +++ b/scapy/layers/tls/extensions.py @@ -12,7 +12,7 @@ from scapy.fields import ByteEnumField, ByteField, EnumField, FieldLenField, \ FieldListField, IntField, PacketField, PacketListField, ShortEnumField, \ - ShortField, StrFixedLenField, StrLenField, XStrLenField + ShortField, StrFixedLenField, StrLenField, XStrLenField, ConditionalField from scapy.packet import Packet, Raw, Padding from scapy.layers.x509 import X509_Extensions from scapy.layers.tls.basefields import _tls_version @@ -46,7 +46,6 @@ 0x16: "encrypt_then_mac", # RFC 7366 0x17: "extended_master_secret", # RFC 7627 0x23: "session_ticket", # RFC 5077 - 0x28: "key_share", 0x29: "pre_shared_key", 0x2a: "early_data", 0x2b: "supported_versions", @@ -55,6 +54,8 @@ 0x2e: "ticket_early_data_info", 0x2f: "certificate_authorities", 0x30: "oid_filters", + 0x32: "signature_algorithms_cert", + 0x33: "key_share", 0x3374: "next_protocol_negotiation", # RFC-draft-agl-tls-nextprotoneg-03 0xff01: "renegotiation_info" # RFC 5746 @@ -496,13 +497,13 @@ class TLS_Ext_SessionTicket(TLS_Ext_Unknown): # RFC 5077 class TLS_Ext_KeyShare(TLS_Ext_Unknown): - name = "TLS Extension - Key Share (dummy class)" - fields_desc = [ShortEnumField("type", 0x28, _tls_ext), + name = "TLS Extension - Key Share (Unknown)" + 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)" + name = "TLS Extension - Pre Shared Key (Unknown)" fields_desc = [ShortEnumField("type", 0x29, _tls_ext), ShortField("len", None)] @@ -517,12 +518,20 @@ class TLS_Ext_SupportedVersions(TLS_Ext_Unknown): name = "TLS Extension - Supported Versions" fields_desc = [ShortEnumField("type", 0x2b, _tls_ext), ShortField("len", None), - FieldLenField("versionslen", None, fmt='B', - length_of="versions"), + # Depending on whether the extension is from + # ServerHello or ClientHello, versionslen may + # or may not exist. + ConditionalField( + FieldLenField("versionslen", None, fmt='B', + length_of="versions"), + lambda x: x.len % 2), FieldListField("versions", [], ShortEnumField("version", None, _tls_version), - length_from=lambda pkt: pkt.versionslen)] + length_from=( + lambda pkt: pkt.versionslen if + pkt.len % 2 else pkt.len - (pkt.len % 2)) + )] class TLS_Ext_Cookie(TLS_Ext_Unknown): @@ -597,7 +606,6 @@ class TLS_Ext_RenegotiationInfo(TLS_Ext_Unknown): # RFC 5746 0x16: TLS_Ext_EncryptThenMAC, 0x17: TLS_Ext_ExtendedMasterSecret, 0x23: TLS_Ext_SessionTicket, - 0x28: TLS_Ext_KeyShare, 0x29: TLS_Ext_PreSharedKey, 0x2a: TLS_Ext_EarlyData, 0x2b: TLS_Ext_SupportedVersions, @@ -605,6 +613,8 @@ class TLS_Ext_RenegotiationInfo(TLS_Ext_Unknown): # RFC 5746 0x2d: TLS_Ext_PSKKeyExchangeModes, 0x2e: TLS_Ext_TicketEarlyDataInfo, # 0x2f: TLS_Ext_CertificateAuthorities, #XXX + # 0x32: TLS_Ext_SignatureAlgorithmsCert, #XXX + 0x33: TLS_Ext_KeyShare, # 0x30: TLS_Ext_OIDFilters, #XXX 0x3374: TLS_Ext_NPN, 0xff01: TLS_Ext_RenegotiationInfo @@ -653,9 +663,14 @@ def addfield(self, pkt, s, i): class _ExtensionsField(StrLenField): + __slots__ = ["msg_type"] islist = 1 holds_packets = 1 + def __init__(self, name, default, **kargs): + self.msg_type = kargs.pop("msg_type", lambda pkt: pkt.msgtype) + StrLenField.__init__(self, name, default, **kargs) + def i2len(self, pkt, i): if i is None: return 0 @@ -690,10 +705,10 @@ def m2i(self, pkt, m): cls = _tls_ext_cls.get(t, TLS_Ext_Unknown) if cls is TLS_Ext_KeyShare: from scapy.layers.tls.keyexchange_tls13 import _tls_ext_keyshare_cls # noqa: E501 - cls = _tls_ext_keyshare_cls.get(pkt.msgtype, TLS_Ext_Unknown) + cls = _tls_ext_keyshare_cls.get(self.msg_type(pkt), TLS_Ext_KeyShare) 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 + cls = _tls_ext_presharedkey_cls.get(self.msg_type(pkt), TLS_Ext_PreSharedKey) # noqa: E501 res.append(cls(m[:tmp_len + 4], tls_session=pkt.tls_session)) m = m[tmp_len + 4:] return res diff --git a/scapy/layers/tls/handshake.py b/scapy/layers/tls/handshake.py index 168caca8cb8..7110ece2c4d 100644 --- a/scapy/layers/tls/handshake.py +++ b/scapy/layers/tls/handshake.py @@ -15,9 +15,10 @@ import struct from scapy.error import log_runtime, warning -from scapy.fields import ByteEnumField, ByteField, EnumField, Field, \ +from scapy.fields import ByteEnumField, ByteField, Field, \ FieldLenField, IntField, PacketField, PacketListField, ShortField, \ - StrFixedLenField, StrLenField, ThreeBytesField, UTCTimeField + StrFixedLenField, StrLenField, ThreeBytesField, UTCTimeField, \ + ShortEnumField from scapy.compat import bytes_hex, orb, raw from scapy.config import conf @@ -29,8 +30,9 @@ from scapy.layers.tls.basefields import (_tls_version, _TLSVersionField, _TLSClientVersionField) from scapy.layers.tls.extensions import (_ExtensionsLenField, _ExtensionsField, - _cert_status_type, TLS_Ext_SupportedVersions, - TLS_Ext_ExtendedMasterSecret) # noqa: E501 + _cert_status_type, + TLS_Ext_SupportedVersions, + TLS_Ext_ExtendedMasterSecret) from scapy.layers.tls.keyexchange import (_TLSSignature, _TLSServerParamsField, _TLSSignatureField, ServerRSAParams, SigAndHashAlgsField, _tls_hash_sig, @@ -136,7 +138,10 @@ class _SessionIDField(StrLenField): """ opaque SessionID<0..32>; section 7.4.1.2 of RFC 4346 """ - pass + def i2repr(self, pkt, x): + if x is None: + return repr(x) + return repr_hex(self.i2h(pkt, x)) class _CipherSuitesField(StrLenField): @@ -294,16 +299,26 @@ def tls_session_update(self, msg_str): if self.ext: for e in self.ext: if isinstance(e, TLS_Ext_SupportedVersions): - if self.tls_session.tls13_early_secret is None: - # this is not recomputed if there was a TLS 1.3 HRR - self.tls_session.compute_tls13_early_secrets() - break + if 0x0304 in e.versions: + if self.tls_session.tls13_early_secret is None: + # this is not recomputed if there was a TLS 1.3 HRR + self.tls_session.compute_tls13_early_secrets() + break ############################################################################### # ServerHello # ############################################################################### +# https://tools.ietf.org/html/rfc8446#section-4.1.3 +_TLS_RetryRequestMagic = b'\xcf!\xadt\xe5\x9aa\x11\xbe\x1d\x8c\x02\x1ee' + \ + b'\xb8\x91\xc2\xa2\x11\x16z\xbb\x8c^\x07\x9e\t' + \ + b'\xe2\xc8\xa83\x9c' +# Tricky old trick (see the TODO in TLSServerHello) +_TLS_RetryRequestMagic_GMT = struct.unpack("!I", _TLS_RetryRequestMagic[:4])[0] +_TLS_RetryRequestMagic_RDM = _TLS_RetryRequestMagic[4:] + + class TLSServerHello(TLSClientHello): """ TLS ServerHello, with abilities to handle extensions. @@ -320,14 +335,16 @@ class TLSServerHello(TLSClientHello): _TLSVersionField("version", None, _tls_version), # _TLSRandomBytesField("random_bytes", None, 32), - _GMTUnixTimeField("gmt_unix_time", None), - _TLSRandomBytesField("random_bytes", None, 28), + # TODO: improve those two (same in ClientHello), so that + # are only one single random_bytes when TLS 1.3 + _GMTUnixTimeField("gmt_unix_time", None), # XXX + _TLSRandomBytesField("random_bytes", None, 28), # XXX FieldLenField("sidlen", None, length_of="sid", fmt="B"), _SessionIDField("sid", "", length_from=lambda pkt: pkt.sidlen), - EnumField("cipher", None, _tls_cipher_suites), + ShortEnumField("cipher", None, _tls_cipher_suites), _CompressionMethodsField("comp", [0], _tls_compression_algs, itemfmt="B", @@ -337,17 +354,18 @@ class TLSServerHello(TLSClientHello): _ExtensionsField("ext", None, length_from=lambda pkt: (pkt.msglen - (pkt.sidlen or 0) - # noqa: E501 - 38))] + 38), + msg_type=( + lambda pkt: 6 if ( + pkt.gmt_unix_time == \ + _TLS_RetryRequestMagic_GMT and \ + pkt.random_bytes == \ + _TLS_RetryRequestMagic_RDM + ) else 2 + ) + )] # 40)) ] - @classmethod - def dispatch_hook(cls, _pkt=None, *args, **kargs): - if _pkt and len(_pkt) >= 6: - version = struct.unpack("!H", _pkt[4:6])[0] - if version == 0x0304 or version > 0x7f00: - return TLS13ServerHello - return TLSServerHello - def post_build(self, p, pay): if self.random_bytes is None: p = p[:10] + randstring(28) + p[10 + 28:] @@ -365,74 +383,28 @@ def tls_session_update(self, msg_str): """ super(TLSClientHello, self).tls_session_update(msg_str) - self.tls_session.tls_version = self.version - self.random_bytes = msg_str[10:38] - self.tls_session.server_random = (struct.pack('!I', - self.gmt_unix_time) + - self.random_bytes) - self.tls_session.sid = self.sid + s = self.tls_session + s.tls_version = self.version + s.server_random = (struct.pack('!I', + self.gmt_unix_time) + + self.random_bytes) + s.sid = self.sid - # EXTMS + # EXT process if self.ext: for e in self.ext: if isinstance(e, TLS_Ext_ExtendedMasterSecret): - self.tls_session.extms = True - break - - cs_cls = None - if self.cipher: - cs_val = self.cipher - if cs_val not in _tls_cipher_suites_cls: - warning("Unknown cipher suite %d from ServerHello" % cs_val) - # we do not try to set a default nor stop the execution - else: - cs_cls = _tls_cipher_suites_cls[cs_val] - - comp_cls = Comp_NULL - if self.comp: - comp_val = self.comp[0] - if comp_val not in _tls_compression_algs_cls: - err = "Unknown compression alg %d from ServerHello" % comp_val - warning(err) - comp_val = 0 - comp_cls = _tls_compression_algs_cls[comp_val] - - connection_end = self.tls_session.connection_end - self.tls_session.pwcs = writeConnState(ciphersuite=cs_cls, - compression_alg=comp_cls, - connection_end=connection_end, - tls_version=self.version) - self.tls_session.prcs = readConnState(ciphersuite=cs_cls, - compression_alg=comp_cls, - connection_end=connection_end, - tls_version=self.version) - - -class TLS13ServerHello(TLSClientHello): - """ TLS 1.3 ServerHello """ - name = "TLS 1.3 Handshake - Server Hello" - fields_desc = [ByteEnumField("msgtype", 2, _tls_handshake_type), - ThreeBytesField("msglen", None), - _TLSVersionField("version", None, _tls_version), - _TLSRandomBytesField("random_bytes", None, 32), - EnumField("cipher", None, _tls_cipher_suites), - _ExtensionsLenField("extlen", None, length_of="ext"), - _ExtensionsField("ext", None, - length_from=lambda pkt: (pkt.msglen - - 38))] - - def tls_session_update(self, msg_str): - """ - Either for parsing or building, we store the server_random along with - the raw string representing this handshake message. We also store the - cipher suite (if recognized), and finally we instantiate the write and - read connection states. - """ - super(TLSClientHello, self).tls_session_update(msg_str) + s.extms = True + continue + if isinstance(e, TLS_Ext_SupportedVersions): + if 0x0304 in e.versions: + s.tls_version = 0x0304 + self.name = "TLS 1.3 Handshake - Server Hello" + continue - s = self.tls_session - s.tls_version = self.version - s.server_random = self.random_bytes + is_tls13 = s.tls_version >= 0x0304 + if is_tls13 and s.server_random == _TLS_RetryRequestMagic: + self.name = "TLS 1.3 Handshake - Hello Retry Request" cs_cls = None if self.cipher: @@ -444,20 +416,40 @@ def tls_session_update(self, msg_str): cs_cls = _tls_cipher_suites_cls[cs_val] connection_end = s.connection_end - s.pwcs = writeConnState(ciphersuite=cs_cls, - connection_end=connection_end, - tls_version=self.version) - s.triggered_pwcs_commit = True - s.prcs = readConnState(ciphersuite=cs_cls, - connection_end=connection_end, - tls_version=self.version) - s.triggered_prcs_commit = True - - if self.tls_session.tls13_early_secret is None: - # In case the connState was not pre-initialized, we could not - # compute the early secrets at the ClientHello, so we do it here. - self.tls_session.compute_tls13_early_secrets() - s.compute_tls13_handshake_secrets() + if is_tls13: # TLS 1.3 + # comp is ignored in TLS 1.3 + s.pwcs = writeConnState(ciphersuite=cs_cls, + connection_end=connection_end, + tls_version=s.tls_version) + s.triggered_pwcs_commit = True + s.prcs = readConnState(ciphersuite=cs_cls, + connection_end=connection_end, + tls_version=s.tls_version) + s.triggered_prcs_commit = True + if self.tls_session.tls13_early_secret is None: + # In case the connState was not pre-initialized, we could not + # compute the early secrets at the ClientHello, so we do it + # here. + self.tls_session.compute_tls13_early_secrets() + s.compute_tls13_handshake_secrets() + else: # TLS 1.2 + comp_cls = Comp_NULL + if self.comp: + comp_val = self.comp[0] + if comp_val not in _tls_compression_algs_cls: + err = ("Unknown compression alg %d from" + + "ServerHello" % comp_val) + warning(err) + comp_val = 0 + comp_cls = _tls_compression_algs_cls[comp_val] + s.pwcs = writeConnState(ciphersuite=cs_cls, + compression_alg=comp_cls, + connection_end=connection_end, + tls_version=s.tls_version) + s.prcs = readConnState(ciphersuite=cs_cls, + compression_alg=comp_cls, + connection_end=connection_end, + tls_version=s.tls_version) ############################################################################### @@ -844,7 +836,7 @@ class TLSCertificateRequest(_TLSHandshake): SigAndHashAlgsLenField("sig_algs_len", None, length_of="sig_algs"), SigAndHashAlgsField("sig_algs", [0x0403, 0x0401, 0x0201], - EnumField("hash_sig", None, _tls_hash_sig), # noqa: E501 + ByteEnumField("hash_sig", None, _tls_hash_sig), # noqa: E501 length_from=lambda pkt: pkt.sig_algs_len), # noqa: E501 FieldLenField("certauthlen", None, fmt="!H", length_of="certauth"), @@ -987,9 +979,6 @@ def tls_session_update(self, msg_str): self.tls_session.session_hash = hash_object.digest(to_hash) - - - ############################################################################### # Finished # ############################################################################### @@ -1279,7 +1268,7 @@ def post_dissection_tls_session_update(self, msg_str): _tls_handshake_cls = {0: TLSHelloRequest, 1: TLSClientHello, 2: TLSServerHello, 3: TLSHelloVerifyRequest, - 4: TLSNewSessionTicket, 6: TLSHelloRetryRequest, + 4: TLSNewSessionTicket, 8: TLSEncryptedExtensions, 11: TLSCertificate, 12: TLSServerKeyExchange, 13: TLSCertificateRequest, 14: TLSServerHelloDone, 15: TLSCertificateVerify, diff --git a/scapy/layers/tls/keyexchange_tls13.py b/scapy/layers/tls/keyexchange_tls13.py index 951dbeb0090..934563679c0 100644 --- a/scapy/layers/tls/keyexchange_tls13.py +++ b/scapy/layers/tls/keyexchange_tls13.py @@ -135,7 +135,7 @@ def extract_padding(self, s): class TLS_Ext_KeyShare_CH(TLS_Ext_Unknown): name = "TLS Extension - Key Share (for ClientHello)" - fields_desc = [ShortEnumField("type", 0x28, _tls_ext), + fields_desc = [ShortEnumField("type", 0x33, _tls_ext), ShortField("len", None), FieldLenField("client_shares_len", None, length_of="client_shares"), @@ -169,14 +169,14 @@ def post_dissection(self, r): class TLS_Ext_KeyShare_HRR(TLS_Ext_Unknown): name = "TLS Extension - Key Share (for HelloRetryRequest)" - fields_desc = [ShortEnumField("type", 0x28, _tls_ext), + fields_desc = [ShortEnumField("type", 0x33, _tls_ext), ShortField("len", None), ShortEnumField("selected_group", None, _tls_named_groups)] class TLS_Ext_KeyShare_SH(TLS_Ext_Unknown): name = "TLS Extension - Key Share (for ServerHello)" - fields_desc = [ShortEnumField("type", 0x28, _tls_ext), + fields_desc = [ShortEnumField("type", 0x33, _tls_ext), ShortField("len", None), PacketField("server_share", None, KeyShareEntry)] @@ -275,7 +275,7 @@ class PSKBinderEntry(Packet): class TLS_Ext_PreSharedKey_CH(TLS_Ext_Unknown): # XXX define post_build and post_dissection methods name = "TLS Extension - Pre Shared Key (for ClientHello)" - fields_desc = [ShortEnumField("type", 0x28, _tls_ext), + fields_desc = [ShortEnumField("type", 0x33, _tls_ext), ShortField("len", None), FieldLenField("identities_len", None, length_of="identities"), diff --git a/scapy/layers/tls/record.py b/scapy/layers/tls/record.py index 9a4925900b9..4c2a9c2f6a4 100644 --- a/scapy/layers/tls/record.py +++ b/scapy/layers/tls/record.py @@ -23,11 +23,12 @@ from scapy.layers.inet import TCP from scapy.layers.tls.session import _GenericTLSSessionInheritance from scapy.layers.tls.handshake import (_tls_handshake_cls, _TLSHandshake, - TLS13ServerHello) + TLSServerHello) from scapy.layers.tls.basefields import (_TLSVersionField, _tls_version, _TLSIVField, _TLSMACField, _TLSPadField, _TLSPadLenField, - _TLSLengthField, _tls_type) + _TLSLengthField, _tls_type, + _tls_type_13) from scapy.layers.tls.crypto.pkcs1 import pkcs_i2osp from scapy.layers.tls.crypto.cipher_aead import AEADTagError from scapy.layers.tls.crypto.cipher_stream import Cipher_NULL @@ -195,7 +196,7 @@ def addfield(self, pkt, s, val): res += self.i2m(pkt, p) if (isinstance(pkt, _GenericTLSSessionInheritance) and _tls_version_check(pkt.tls_session.tls_version, 0x0304) and - not isinstance(pkt, TLS13ServerHello)): + not isinstance(pkt, TLSServerHello)): return s + res if not pkt.type: pkt.type = 0 @@ -282,12 +283,12 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): responsible for low-minded extensibility choices. """ if _pkt and len(_pkt) >= 2: - byte0 = orb(_pkt[0]) - byte1 = orb(_pkt[1]) - if (byte0 not in _tls_type) or (byte1 != 3): + type_ = orb(_pkt[0]) + version_ = orb(_pkt[1]) + if (type_ not in _tls_type) or (version_ != 3): from scapy.layers.tls.record_sslv2 import SSLv2 return SSLv2 - else: + elif type_ in _tls_type_13: s = kargs.get("tls_session", None) if s and _tls_version_check(s.tls_version, 0x0304): if s.rcs and not isinstance(s.rcs.cipher, Cipher_NULL): @@ -476,7 +477,8 @@ def pre_dissect(self, s): # Authenticated encryption # crypto/cipher_aead.py prints a warning for integrity failure if (conf.crypto_valid_advanced and - isinstance(self.tls_session.rcs.cipher, Cipher_CHACHA20_POLY1305)): # noqa: E501 + isinstance(self.tls_session.rcs.cipher, + Cipher_CHACHA20_POLY1305)): iv = b"" cfrag, mac = self._tls_auth_decrypt(hdr, efrag) else: diff --git a/scapy/layers/tls/record_tls13.py b/scapy/layers/tls/record_tls13.py index 30e770e7d10..93623150a3f 100644 --- a/scapy/layers/tls/record_tls13.py +++ b/scapy/layers/tls/record_tls13.py @@ -90,7 +90,7 @@ class TLS13(_GenericTLSSessionInheritance): __slots__ = ["deciphered_len"] name = "TLS 1.3" fields_desc = [ByteEnumField("type", 0x17, _tls_type), - _TLSVersionField("version", 0x0301, _tls_version), + _TLSVersionField("version", 0x0303, _tls_version), _TLSLengthField("len", None), _TLSInnerPlaintextField("inner", TLSInnerPlaintext()), _TLSMACField("auth_tag", None)] diff --git a/test/tls13.uts b/test/tls13.uts index f8aa9b66190..3005aad5b01 100644 --- a/test/tls13.uts +++ b/test/tls13.uts @@ -1,15 +1,19 @@ -% Tests for TLS 1.3 +% Read a TLS 1.3 session # # Try me with : # bash test/run_tests -t test/tls13.uts -F -+ Read a TLS 1.3 session # /!\ These tests will not catch our 'INTEGRITY CHECK FAILED's. /!\ # We deem the knowledge of the plaintext sufficient for passing... -= Reading TLS 1.3 test session (vectors 5 from draft-ietf-tls-tls13-vectors-00) +# https://tools.ietf.org/html/draft-ietf-tls-tls13-vectors-07#section-5 + ++ Reading TLS 1.3 test session (vectors 5 from draft-ietf-tls-tls13-vectors-07) ~ crypto + += Load utils + import binascii from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateNumbers from cryptography.hazmat.backends import default_backend @@ -17,250 +21,330 @@ from cryptography.hazmat.backends import default_backend def clean(s): return binascii.unhexlify(''.join(c for c in s if c.isalnum())) += Dissect ClientHello : The client initiates a handshake with an X25519 + clientHello1 = clean(""" - 16030100ae010000 aa0303d9e9898df6 - 3d43adbe64a2634f 0b63bcdc4019a3e5 26bc013a6042e05b - 14555c0000061301 130313020100007b 0000000b00090000 - 06736572766572ff 01000100000a0008 0006001d00170018 - 002800260024001d 002005efa94d13f5 adcd14219379d5a3 - 7dbce4721d9294e5 72c6651aeb761838 815b002b0003027f - 12000d0020001e04 0305030603020308 0408050806040105 - 0106010201040205 0206020202002d00 020101 + 16 03 01 00 b4 01 00 00 b0 03 03 b0 + b1 c5 a5 aa 37 c5 91 9f 2e d1 d5 c6 ff f7 fc b7 84 97 16 94 5a + 2b 8c ee 92 58 a3 46 67 7b 6f 00 00 06 13 01 13 03 13 02 01 00 + 00 81 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 + 00 00 0a 00 08 00 06 00 1d 00 17 00 18 00 33 00 26 00 24 00 1d + 00 20 e8 e8 e3 f3 b9 3a 25 ed 97 a1 4a 7d ca cb 8a 27 2c 62 88 + e5 85 c6 48 4d 05 26 2f ca d0 62 ad 1f 00 2b 00 03 02 03 04 00 + 0d 00 20 00 1e 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 + 05 01 06 01 02 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 + 1c 00 02 40 01 """) -t = TLS(clientHello1) +t1 = TLS(clientHello1) + += Dissect ServerHello: The server however prefers P-256 [FIPS186] and sends a HelloRetryRequest +# Note: The HelloRetryRequest uses the same handshake message type as +# a ServerHello and so is labeled as ServerHello here. helloRetryRequest = clean(""" - 160301000e060000 0a7f120006002800 020017 + 16 03 03 00 b0 02 00 00 ac 03 03 cf + 21 ad 74 e5 9a 61 11 be 1d 8c 02 1e 65 b8 91 c2 a2 11 16 7a bb + 8c 5e 07 9e 09 e2 c8 a8 33 9c 00 13 01 00 00 84 00 33 00 02 00 + 17 00 2c 00 74 00 72 71 dc d0 4b b8 8b c3 18 91 19 39 8a 00 00 + 00 00 ee fa fc 76 c1 46 b8 23 b0 96 f8 aa ca d3 65 dd 00 30 95 + 3f 4e df 62 56 36 e5 f2 1b b2 e2 3f cc 65 4b 1b 5b 40 31 8d 10 + d1 37 ab cb b8 75 74 e3 6e 8a 1f 02 5f 7d fa 5d 6e 50 78 1b 5e + da 4a a1 5b 0c 8b e7 78 25 7d 16 aa 30 30 e9 e7 84 1d d9 e4 c0 + 34 22 67 e8 ca 0c af 57 1f b2 b7 cf f0 f9 34 b0 00 2b 00 02 03 + 04 """) -t = TLS(helloRetryRequest, tls_session=t.tls_session.mirror()) +t2 = TLS(helloRetryRequest, tls_session=t1.tls_session.mirror()) + += Dissect ClientHello again, this time using P-256 secp256r1_client_privkey = clean(""" - 11fa48d153c917ff d89dff13140760a1 - 36265d399fa9f10e 2d766d42a6c84e90 + ab 54 73 46 7e 19 34 6c eb 0a 04 14 e4 + 1d a2 1d 4d 24 45 bc 30 25 af e9 7c 4e 8d c8 d5 13 da 39 """) clientHello2 = clean(""" - 16030100cf010000 cb0303d9e9898df6 - 3d43adbe64a2634f 0b63bcdc4019a3e5 26bc013a6042e05b - 14555c0000061301 130313020100009c 0000000b00090000 - 06736572766572ff 01000100000a0008 0006001d00170018 - 0028004700450017 0041041e5a785f54 17fb18db42938435 - 34a5c0ba6e744baa 6846d0b32f4e9ea3 922724a08f2adb09 - f071f81402e7fd8c a33b76abe1cd556f d3e8fe20e0fd2e82 - 02f969002b000302 7f12000d0020001e 0403050306030203 - 0804080508060401 0501060102010402 050206020202002d 00020101 + 16 03 03 02 00 01 00 01 fc 03 03 b0 + b1 c5 a5 aa 37 c5 91 9f 2e d1 d5 c6 ff f7 fc b7 84 97 16 94 5a + 2b 8c ee 92 58 a3 46 67 7b 6f 00 00 06 13 01 13 03 13 02 01 00 + 01 cd 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 + 00 00 0a 00 08 00 06 00 1d 00 17 00 18 00 33 00 47 00 45 00 17 + 00 41 04 a6 da 73 92 ec 59 1e 17 ab fd 53 59 64 b9 98 94 d1 3b + ef b2 21 b3 de f2 eb e3 83 0e ac 8f 01 51 81 26 77 c4 d6 d2 23 + 7e 85 cf 01 d6 91 0c fb 83 95 4e 76 ba 73 52 83 05 34 15 98 97 + e8 06 57 80 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 + 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 + 02 06 02 02 02 00 2c 00 74 00 72 71 dc d0 4b b8 8b c3 18 91 19 + 39 8a 00 00 00 00 ee fa fc 76 c1 46 b8 23 b0 96 f8 aa ca d3 65 + dd 00 30 95 3f 4e df 62 56 36 e5 f2 1b b2 e2 3f cc 65 4b 1b 5b + 40 31 8d 10 d1 37 ab cb b8 75 74 e3 6e 8a 1f 02 5f 7d fa 5d 6e + 50 78 1b 5e da 4a a1 5b 0c 8b e7 78 25 7d 16 aa 30 30 e9 e7 84 + 1d d9 e4 c0 34 22 67 e8 ca 0c af 57 1f b2 b7 cf f0 f9 34 b0 00 + 2d 00 02 01 01 00 1c 00 02 40 01 00 15 00 af 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 """) -t = TLS(clientHello2, tls_session=t.tls_session.mirror()) -pubnum = t.tls_session.tls13_client_pubshares["secp256r1"].public_numbers() +t3 = TLS(clientHello2) +pubnum = t3.tls_session.tls13_client_pubshares["secp256r1"].public_numbers() privnum = EllipticCurvePrivateNumbers(pkcs_os2ip(secp256r1_client_privkey), pubnum) privkey = privnum.private_key(default_backend()) -t.tls_session.tls13_client_privshares["secp256r1"] = privkey +t3.tls_session.tls13_client_privshares["secp256r1"] = privkey + += Dissect ServerHello answer #secp256r1_server_privkey = clean(""" -# ff265d2062c70725 ca22513e1e6841ff -# 475e8a00421f0818 186edd1c0080cc6a +# 11 31 54 5d 0b af 79 dd ce 9b 87 f0 69 45 78 1a +# 57 dd 18 ef 37 8d cd 20 60 f8 f9 a5 69 02 7e d8 # """) serverHello = clean(""" - 1603010073020000 6f7f1296ff693075 - d8465651a9c28773 f5496542206ba390 199b9c997545d9a1 - 2666151301004900 2800450017004104 8a4d09cde58dbc04 - 1955b9a41a43c169 6dc5429ffa96f9cd 194a863ac782f181 - 59f072b4f610215d 86407dd7368b754a b2e64f2c1b3f9d45 - 7c264e2b1781a36b + 16 03 03 00 7b 02 00 00 77 03 03 bb + 34 1d 84 7f d7 89 c4 7c 38 71 72 dc 0c 9b f1 47 fc ca cb 50 43 + d8 6c a4 c5 98 d3 ff 57 1b 98 00 13 01 00 00 4f 00 33 00 45 00 + 17 00 41 04 58 3e 05 4b 7a 66 67 2a e0 20 ad 9d 26 86 fc c8 5b + 5a d4 1a 13 4a 0f 03 ee 72 b8 93 05 2b d8 5b 4c 8d e6 77 6f 5b + 04 ac 07 d8 35 40 ea b3 e3 d9 c5 47 bc 65 28 c4 31 7d 29 46 86 + 09 3a 6c ad 7d 00 2b 00 02 03 04 """) -t = TLS(serverHello, tls_session=t.tls_session.mirror()) +t4 = TLS(serverHello, tls_session=t3.tls_session.mirror()) + += Dissect Server Encoded certificate serverEncHS = clean(""" - 170301029081de4f cfd700da4573d570 - 5942f14a11e569aa 9aacc95260520102 6f74f2b2ad6abe08 - 7b53a4940ff94208 9e02d3159b1c6f11 75d7fcb51abad6fd - d4f7ff4af6590b47 16c1d90e1031e1a1 e32079f531108c6b - 9f79d6120319e0a3 73010e82d780a8f9 c3fdf8474840cdb6 - 7e4943d3808a27cd 5d9375c766a95ef4 8393c235d83ad26a - 20628671793f75df aa0be78b11fed206 6506d19a769d9d32 - adc0437784994359 ef5e452609353670 1c46004cf6fc252e - 546e797238c73b94 b073461158301f78 1498917c32dc0ece - 658a53790c667397 f7744775c2bef907 b5f7d5677b2e57fe - 7c4bfd43c7ad1ee4 6fd400c3d3c3c05f e8775f055263e98a - 692b49a818d0f698 4400c1db2f429fa8 9fb61d523398e1d0 - 2bc5c393027146c0 f326032d18cb8283 473f2b6d554df942 - c7b1a0050694c7b2 bf31a816f7ff77f1 d7db873dbb6e4646 - acabfa73c317a34c e6212a3469f549e6 cde71ab229a6f220 - acda60832b510663 02a23d02c734bd5e 71b04fb248ca47ba - 0c7b1fd28fee9b5d 86e6b1a6a2a1a43e 3831210519f54134 - c96486d11ef3125f 74969785690487e0 aa5c0a310ebf9d31 - 95ec5543af8a6ffb 710eb0a90285960d c1ccdc10ecee9669 - 9171e97eae526a17 205012ab6f262e44 31ae9a70ff2ed7bd - 966ef6bd4563f56a 7a14970dcabf97ae 7e4354db1ea27548 - c55c11542ad07bcd 6f47a7143b86c4e6 678ce7dc6d51a1b7 - 75687644d6526efa 3c864f592819e7b7 f9f1bbc02ed8821a - e66019b240b41f5e ebf9475069700030 7122f7c8a8d6c0da - a264c63183238d72 0eacb86879fab9ba 8a673c51a52c8284 - 75e3211223cd2238 bd8b8a934af3e4dd e10e788df23ad6d8 - 51d68b78082ac667 a854356415e7858b e526307332990d8c - c38a5dc4cfc22a2c a2bdd9126a2ce13d 7015264921 + 17 03 03 02 96 99 be e2 0b af 5b 7f + c7 27 bf ab 62 23 92 8a 38 1e 6d 0c f9 c4 da 65 3f 9d 2a 7b 23 + f7 de 11 cc e8 42 d5 cf 75 63 17 63 45 0f fb 8b 0c c1 d2 38 e6 + 58 af 7a 12 ad c8 62 43 11 4a b1 4a 1d a2 fa e4 26 21 ce 48 3f + b6 24 2e ab fa ad 52 56 6b 02 b3 1d 2e dd ed ef eb 80 e6 6a 99 + 00 d5 f9 73 b4 0c 4f df 74 71 9e cf 1b 68 d7 f9 c3 b6 ce b9 03 + ca 13 dd 1b b8 f8 18 7a e3 34 17 e1 d1 52 52 2c 58 22 a1 a0 3a + d5 2c 83 8c 55 95 3d 61 02 22 87 4c ce 8e 17 90 b2 29 a2 aa 0b + 53 c8 d3 77 ee 72 01 82 95 1d c6 18 1d c5 d9 0b d1 f0 10 5e d1 + e8 4a a5 f7 59 57 c6 66 18 97 07 9e 5e a5 00 74 49 e3 19 7b dc + 7c 9b ee ed dd ea fd d8 44 af a5 c3 15 ec fe 65 e5 76 af e9 09 + 81 28 80 62 0e c7 04 8b 42 d7 f5 c7 8d 76 f2 99 d6 d8 25 34 bd + d8 f5 12 fe bc 0e d3 81 4a ca 47 0c d8 00 0d 3e 1c b9 96 2b 05 + 2f bb 95 0d f6 83 a5 2c 2b a7 7e d3 71 3b 12 29 37 a6 e5 17 09 + 64 e2 ab 79 69 dc d9 80 b3 db 9b 45 8d a7 60 31 24 d6 dc 00 5e + 4d 6e 04 b4 d0 c4 ba f3 27 5d b8 27 db ba 0a 6d b0 96 72 17 1f + c0 57 b3 85 1d 7e 02 68 41 e2 97 8f bd 23 46 bb ef dd 03 76 bb + 11 08 fe 9a cc 92 18 9f 56 50 aa 5e 85 d8 e8 c7 b6 7a c5 10 db + a0 03 d3 d7 e1 63 50 bb 66 d4 50 13 ef d4 4c 9b 60 7c 0d 31 8c + 4c 7d 1a 1f 5c bc 57 e2 06 11 80 4e 37 87 d7 b4 a4 b5 f0 8e d8 + fd 70 bd ae ad e0 22 60 b1 2a b8 42 ef 69 0b 4a 3e e7 91 1e 84 + 1b 37 4e cd 5e bb bc 2a 54 d0 47 b6 00 33 6d d7 d0 c8 8b 4b c1 + 0e 58 ee 6c b6 56 de 72 47 fa 20 d8 e9 1d eb 84 62 86 08 cf 80 + 61 5b 62 e9 6c 14 91 c7 ac 37 55 eb 69 01 40 5d 34 74 fe 1a c7 + 9d 10 6a 0c ee 56 c2 57 7f c8 84 80 f9 6c b6 b8 c6 81 b7 b6 8b + 53 c1 46 09 39 08 f3 50 88 81 75 bd fb 0b 1e 31 ad 61 e3 0b a0 + ad fe 6d 22 3a a0 3c 07 83 b5 00 1a 57 58 7c 32 8a 9a fc fc fb + 97 8d 1c d4 32 8f 7d 9d 60 53 0e 63 0b ef d9 6c 0c 81 6e e2 0b + 01 00 76 8a e2 a6 df 51 fc 68 f1 72 74 0a 79 af 11 39 8e e3 be + 12 52 49 1f a9 c6 93 47 9e 87 7f 94 ab 7c 5f 8c ad 48 02 03 e6 + ab 7b 87 dd 71 e8 a0 72 91 13 df 17 f5 ee e8 6c e1 08 d1 d7 20 + 07 ec 1c d1 3c 85 a6 c1 49 62 1e 77 b7 d7 8d 80 5a 30 f0 be 03 + 0c 31 5e 54 """) -t = TLS(serverEncHS, tls_session=t.tls_session) +t5 = TLS(serverEncHS, tls_session=t4.tls_session) + += Dissect Client Finished clientFinished = clean(""" - 170301003543adad e592362412fb77d7 - 28b181c01b77cd62 a661e4125e6f9851 826e418f4c292ec6 - 3254e8b0342d65db 8a7f074eed527ea6 98a6 + 17 03 03 00 35 d7 4f 19 23 c6 62 fd + 34 13 7c 6f 50 2f 3d d2 b9 3d 95 1d 1b 3b c9 7e 42 af e2 3c 31 + ab ea 92 fe 91 b4 74 99 9e 85 e3 b7 91 ce 25 2f e8 c3 e9 f9 39 + a4 12 0c b2 """) -t = TLS(clientFinished, tls_session=t.tls_session.mirror()) +t6 = TLS(clientFinished, tls_session=t5.tls_session.mirror()) + += Dissect Client alert record clientRecord = clean(""" - 17030100131ef5c9 e7205f31a1edf9b1 - 3600fec1271e4f5d + 17 03 03 00 13 2e a6 cd f7 49 19 60 + 23 e2 b3 a4 94 91 69 55 36 42 60 47 """) -t = TLS(clientRecord, tls_session=t.tls_session) +t7 = TLS(clientRecord, tls_session=t6.tls_session) + += Dissect Server alert record serverRecord = clean(""" - 170301001350ff6e 907c508b6b191ff6 - 094faf4c0b32d6a8 + 17 03 03 00 13 51 9f c5 07 5c b0 88 + 43 49 75 9f f9 ef 6f 01 1b b4 c6 f2 """) -t = TLS(serverRecord, tls_session=t.tls_session.mirror()) +t8 = TLS(serverRecord, tls_session=t7.tls_session.mirror()) -alert = t.inner.msg[0] +alert = t8.inner.msg[0] assert(isinstance(alert, TLSAlert)) alert.level == 1 and alert.descr == 0 -= Reading TLS 1.3 test session (vectors 3 from draft-ietf-tls-tls13-vectors-00) ++ Reading TLS 1.3 test session (vectors 3 from draft-ietf-tls-tls13-vectors-00) ~ crypto_advanced + += Dissect ClientHello handshake message + from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey x25519_client_privkey = clean(""" - 00b4198a84ed6a7c 218702891735239d - 40b7c66505330364 3d3c67f7458ecbc9 + 49 af 42 ba 7f 79 94 85 2d 71 3e f2 78 + 4b cb ca a7 91 1d e2 6a dc 56 42 cb 63 45 40 e7 ea 50 05 """) clientHello = clean(""" - 1603010200010001 fc03039a464db650 - dcc81fed6f1fea63 5f15861574c0ed0b fb5778de7724fb92 - 7c5ef100003e1301 13031302c02bc02f cca9cca8c00ac009 - c013c023c027c014 009eccaa00330032 006700390038006b - 00160013009c002f 003c0035003d000a 0005000401000195 - 001500fc00000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000000000000 - 0000000000000000 0000000000000000 0000000b00090000 - 06736572766572ff 01000100000a0014 0012001d00170018 - 0019010001010102 01030104000b0002 0100002300000028 - 00260024001d0020 35e58b160db6124f 01a1d2475a22b72a - bd6896701eed4c7e fd6124ee231ba458 002b0007067f1203 - 030302000d002000 1e04030503060302 0308040805080604 - 0105010601020104 0205020602020200 2d00020101 + 16 03 01 00 c4 01 00 00 c0 03 03 cb + 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 + ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 + 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 + 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 + 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d + e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d + 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e + 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 + 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 """) -t = TLS(clientHello) +t1 = TLS(clientHello) privkey = X25519PrivateKey._from_private_bytes(x25519_client_privkey) -t.tls_session.tls13_client_privshares["x25519"] = privkey +t1.tls_session.tls13_client_privshares["x25519"] = privkey + += Dissect ServerHello handshake message x25519_server_privkey = clean(""" - 03d43f48ed52076f 4ce9bab73d1f39ec - 689cf304075829f5 2b90f9f13bea6f34 + b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56 + 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e """) serverHello = clean(""" - 1603010052020000 4e7f1298e3436403 - 8683391cbec1039a a0fba2f496d8c8e6 327151cc94bbc5ef - 7390751301002800 280024001d0020a2 0ed1b7f2d96a7f12 - 568f0e460bb0fc86 dc8d1db6c07d6b10 d4dc74aaac9219 + 16 03 03 00 5a 02 00 00 56 03 03 a6 + af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 + 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 + 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 + cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04 """) -t = TLS(serverHello, tls_session=t.tls_session.mirror()) +t2 = TLS(serverHello, tls_session=t1.tls_session.mirror()) + += Dissect Certificate Handshake message serverEncHS = clean(""" - 170301029c4e1f34 2dba17a54a09f7a1 - 8ffb2c6a29df17a6 db843044c52861bf 78988527ce366159 - e6a24871b704d2b9 fade56488921796d 719173a753bdfec8 - 0554c8c15e128695 450ccfdde1204ffd 2fb1ecdcd87b8070 - 644eb5a6b86ec951 aba3ed314754a2f3 14d4d2620b92da1f - 28f24b9559d76b67 a7b35c17cc231ba5 77a94fb2be59c74f - 84c8c78bf5faf4cb b2f8a37091580743 3c67d9f4e1b1923a - 3969b85a2ae9064e 34e84363aae43aa9 f58717836a017b9c - 33c3ad733c2fd3ce 288ae362764403d0 102a371047d9e49d - f9b30596262b1704 f0e9839fff5641ba a7041a4bcf9e4d46 - 7108922fc0ea0bc1 48dab2ebdd155f51 76c632be04a7c610 - 3fbc92754dba7962 4f8a09f8e8d65c17 eee87f98636fbc93 - bb734674b80d183c da904200a20d8f15 0a214902b6953209 - aa2431c3973bda3b d92a33878baca7b9 0507f433a55f2fe8 - f0db81898ebacf31 b68eaabfa27c39b6 a2453a322c005030 - 4e60bf53f0402b38 65b43fe5a7454c13 17a2dc76d1323fb1 - aa553996876a0dfe 8e789d6adf3dc85b 0636bb58a96e6aad - 851e7a6fc1dfa796 ec65e33bf9e3c05d 6de35f11e1f32731 - fb9550a60cb75e90 9345eb0edb81f99f cad883cb41d4a3ef - 7cbe671b92a8176b 472772be401b83a4 99b06b7ab0a1d9cd - 795e5ba0b67ce2d6 5c45565028824aa2 08797f405bbcf243 - 27dd69a1d986032f 544b15d110e4d8c4 681cb85c09960adb - 57fb9723eef0e0bb 275552af25fbdfc1 a4215adf14a9dba2 - 4462dd095f1a78f5 6ed6db3de139936f 14b091ab7f4adc81 - c277e68bfb6fd925 d92c06c0a4ddd105 9c071073a8a2e987 - f98948599f27bf6d 1f4369ac6c5a3323 2932fb8aa52ec4e1 - 85790dff0ef5eee0 13b4e90b5bc1cd4a c42b7ce82d856cc0 - f5d1c80400e68d61 b434cec56d437141 1e31849d4cf88862 - 8ba288548df6a19e c4 +17 03 03 02 a2 d1 ff 33 4a 56 f5 bf + f6 59 4a 07 cc 87 b5 80 23 3f 50 0f 45 e4 89 e7 f3 3a f3 5e df + 78 69 fc f4 0a a4 0a a2 b8 ea 73 f8 48 a7 ca 07 61 2e f9 f9 45 + cb 96 0b 40 68 90 51 23 ea 78 b1 11 b4 29 ba 91 91 cd 05 d2 a3 + 89 28 0f 52 61 34 aa dc 7f c7 8c 4b 72 9d f8 28 b5 ec f7 b1 3b + d9 ae fb 0e 57 f2 71 58 5b 8e a9 bb 35 5c 7c 79 02 07 16 cf b9 + b1 18 3e f3 ab 20 e3 7d 57 a6 b9 d7 47 76 09 ae e6 e1 22 a4 cf + 51 42 73 25 25 0c 7d 0e 50 92 89 44 4c 9b 3a 64 8f 1d 71 03 5d + 2e d6 5b 0e 3c dd 0c ba e8 bf 2d 0b 22 78 12 cb b3 60 98 72 55 + cc 74 41 10 c4 53 ba a4 fc d6 10 92 8d 80 98 10 e4 b7 ed 1a 8f + d9 91 f0 6a a6 24 82 04 79 7e 36 a6 a7 3b 70 a2 55 9c 09 ea d6 + 86 94 5b a2 46 ab 66 e5 ed d8 04 4b 4c 6d e3 fc f2 a8 94 41 ac + 66 27 2f d8 fb 33 0e f8 19 05 79 b3 68 45 96 c9 60 bd 59 6e ea + 52 0a 56 a8 d6 50 f5 63 aa d2 74 09 96 0d ca 63 d3 e6 88 61 1e + a5 e2 2f 44 15 cf 95 38 d5 1a 20 0c 27 03 42 72 96 8a 26 4e d6 + 54 0c 84 83 8d 89 f7 2c 24 46 1a ad 6d 26 f5 9e ca ba 9a cb bb + 31 7b 66 d9 02 f4 f2 92 a3 6a c1 b6 39 c6 37 ce 34 31 17 b6 59 + 62 22 45 31 7b 49 ee da 0c 62 58 f1 00 d7 d9 61 ff b1 38 64 7e + 92 ea 33 0f ae ea 6d fa 31 c7 a8 4d c3 bd 7e 1b 7a 6c 71 78 af + 36 87 90 18 e3 f2 52 10 7f 24 3d 24 3d c7 33 9d 56 84 c8 b0 37 + 8b f3 02 44 da 8c 87 c8 43 f5 e5 6e b4 c5 e8 28 0a 2b 48 05 2c + f9 3b 16 49 9a 66 db 7c ca 71 e4 59 94 26 f7 d4 61 e6 6f 99 88 + 2b d8 9f c5 08 00 be cc a6 2d 6c 74 11 6d bd 29 72 fd a1 fa 80 + f8 5d f8 81 ed be 5a 37 66 89 36 b3 35 58 3b 59 91 86 dc 5c 69 + 18 a3 96 fa 48 a1 81 d6 b6 fa 4f 9d 62 d5 13 af bb 99 2f 2b 99 + 2f 67 f8 af e6 7f 76 91 3f a3 88 cb 56 30 c8 ca 01 e0 c6 5d 11 + c6 6a 1e 2a c4 c8 59 77 b7 c7 a6 99 9b bf 10 dc 35 ae 69 f5 51 + 56 14 63 6c 0b 9b 68 c1 9e d2 e3 1c 0b 3b 66 76 30 38 eb ba 42 + f3 b3 8e dc 03 99 f3 a9 f2 3f aa 63 97 8c 31 7f c9 fa 66 a7 3f + 60 f0 50 4d e9 3b 5b 84 5e 27 55 92 c1 23 35 ee 34 0b bc 4f dd + d5 02 78 40 16 e4 b3 be 7e f0 4d da 49 f4 b4 40 a3 0c b5 d2 af + 93 98 28 fd 4a e3 79 4e 44 f9 4d f5 a6 31 ed e4 2c 17 19 bf da + bf 02 53 fe 51 75 be 89 8e 75 0e dc 53 37 0d 2b """) -t = TLS(serverEncHS, tls_session=t.tls_session) +t3 = TLS(serverEncHS, tls_session=t2.tls_session) + += Dissect client Handshake Record clientFinished = clean(""" - 1703010035161e94 818226d7bd618063 - 0804644debc52bdd 661034243217ac45 a084228c82086baa - 4893ecfc969624d6 8e19d88c3e67ccb4 8bdf + 17 03 03 00 35 75 ec 4d c2 38 cc e6 + 0b 29 80 44 a7 1e 21 9c 56 cc 77 b0 51 7f e9 b9 3c 7a 4b fc 44 + d8 7f 38 f8 03 38 ac 98 fc 46 de b3 84 bd 1c ae ac ab 68 67 d7 + 26 c4 05 46 """) -t = TLS(clientFinished, tls_session=t.tls_session.mirror()) +t4 = TLS(clientFinished, tls_session=t3.tls_session.mirror()) + += Dissect HandshakeRecord (NewSessionTicket) serverRecord1 = clean(""" - 17030100bbe6b3e9 89df694688f29f5d - a42d9f56053fc6d2 f73ee23accad26f9 599ee4dcf4e0cf9e - de80128b48156a65 e5e47dee679a8401 1234862b6728fb12 - be5198d5c023d6f2 0c355fc417a5eade 1aff0bf9ecba14c8 - 7277ea7aeb30055e a4d9b37bc12f7517 27ca7a1efc9285f8 - ed5e9e3be42ff475 30f2b7347a90618b 6f7f4eba9b8b6564 - f2159fcfcf09e4b6 2b4b09bb129e7c76 5c877966ca66e5cd - a84cdb6087a07fc0 50c97f275568623c 5d0f459d2b1133d1 - d5d37cd441192da7 + 17 03 03 00 de 3a 6b 8f 90 41 4a 97 + d6 95 9c 34 87 68 0d e5 13 4a 2b 24 0e 6c ff ac 11 6e 95 d4 1d + 6a f8 f6 b5 80 dc f3 d1 1d 63 c7 58 db 28 9a 01 59 40 25 2f 55 + 71 3e 06 1d c1 3e 07 88 91 a3 8e fb cf 57 53 ad 8e f1 70 ad 3c + 73 53 d1 6d 9d a7 73 b9 ca 7f 2b 9f a1 b6 c0 d4 a3 d0 3f 75 e0 + 9c 30 ba 1e 62 97 2a c4 6f 75 f7 b9 81 be 63 43 9b 29 99 ce 13 + 06 46 15 13 98 91 d5 e4 c5 b4 06 f1 6e 3f c1 81 a7 7c a4 75 84 + 00 25 db 2f 0a 77 f8 1b 5a b0 5b 94 c0 13 46 75 5f 69 23 2c 86 + 51 9d 86 cb ee ac 87 aa c3 47 d1 43 f9 60 5d 64 f6 50 db 4d 02 + 3e 70 e9 52 ca 49 fe 51 37 12 1c 74 bc 26 97 68 7e 24 87 46 d6 + df 35 30 05 f3 bc e1 86 96 12 9c 81 53 55 6b 3b 6c 67 79 b3 7b + f1 59 85 68 4f """) -t = TLS(serverRecord1, tls_session=t.tls_session.mirror()) +t5 = TLS(serverRecord1, tls_session=t4.tls_session.mirror()) + += Dissect client application_data record clientRecord1 = clean(""" - 170301004341b540 bf5adeaf9d209001 - 9f0733e281964724 526678a1946852cf 6f586dffacf1151d - bf7c9262ef6ae960 4a423fff339fd7e4 0cc3e7604ae661f0 - afa2f775c3668867 + 17 03 03 00 43 a2 3f 70 54 b6 2c 94 + d0 af fa fe 82 28 ba 55 cb ef ac ea 42 f9 14 aa 66 bc ab 3f 2b + 98 19 a8 a5 b4 6b 39 5b d5 4a 9a 20 44 1e 2b 62 97 4e 1f 5a 62 + 92 a2 97 70 14 bd 1e 3d ea e6 3a ee bb 21 69 49 15 e4 """) -t = TLS(clientRecord1, tls_session=t.tls_session.mirror()) -app_data = t.inner.msg[0] -assert(app_data.data == b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01') +t6 = TLS(clientRecord1, tls_session=t5.tls_session.mirror()) +app_data = t6.inner.msg[0] +data = clean(""" + 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e + 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 + 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 + """) +assert(app_data.data == data) + += Dissect server application_data record serverRecord2 = clean(""" - 17030100438c3168 1fb21f820ef0603c - dc3b9d3deedeb2bb 615aa418fb2590a0 9b0dec00c2299feb - 17c4206f89ab28d2 7a605e288ac9bd69 657593addd1046be - 51b23940f8746634 + 17 03 03 00 43 2e 93 7e 11 ef 4a c7 + 40 e5 38 ad 36 00 5f c4 a4 69 32 fc 32 25 d0 5f 82 aa 1b 36 e3 + 0e fa f9 7d 90 e6 df fc 60 2d cb 50 1a 59 a8 fc c4 9c 4b f2 e5 + f0 a2 1c 00 47 c2 ab f3 32 54 0d d0 32 e1 67 c2 95 5d + """) +t7 = TLS(serverRecord2, tls_session=t6.tls_session.mirror()) +app_data = t7.inner.msg[0] +data = clean(""" + 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e + 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 + 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 """) -t = TLS(serverRecord2, tls_session=t.tls_session.mirror()) -app_data = t.inner.msg[0] -assert(app_data.data == b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01') +assert(app_data.data == data) + += Dissect client alert record clientRecord2 = clean(""" - 17030100131ce9b1 f21ba236bca94455 - ab2aad71c666534a + 17 03 03 00 13 c9 87 27 60 65 56 66 + b7 4d 7f f1 15 3e fd 6d b6 d0 b0 e3 """) -t = TLS(clientRecord2, tls_session=t.tls_session.mirror()) -alert = t.inner.msg[0] +t8 = TLS(clientRecord2, tls_session=t7.tls_session.mirror()) +alert = t8.inner.msg[0] assert(isinstance(alert, TLSAlert)) assert(alert.level == 1 and alert.descr == 0) += Dissect server alert record + serverRecord3 = clean(""" - 1703010013aabcdb 9d293d23fb00deb7 - 11b562afeddffeed + 17 03 03 00 13 b5 8f d6 71 66 eb f5 + 99 d2 47 20 cf be 7e fa 7a 88 64 a9 + """) -t = TLS(serverRecord3, tls_session=t.tls_session.mirror()) -alert = t.inner.msg[0] +t9 = TLS(serverRecord3, tls_session=t8.tls_session.mirror()) +alert = t9.inner.msg[0] assert(isinstance(alert, TLSAlert)) alert.level == 1 and alert.descr == 0 diff --git a/tls-13-handshake.pcap b/tls-13-handshake.pcap new file mode 100644 index 0000000000000000000000000000000000000000..22495170883d22721585f4c0a2978e3791fcf93d GIT binary patch literal 8525 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 i2-C!`4C^ Date: Sat, 1 Dec 2018 21:19:31 +0100 Subject: [PATCH 4/8] Try to fix tls_version handling (contains debug logs) --- scapy/layers/tls/basefields.py | 3 --- scapy/layers/tls/crypto/cipher_aead.py | 8 ++++---- scapy/layers/tls/record.py | 20 ++++++-------------- scapy/layers/tls/record_tls13.py | 4 +++- scapy/layers/tls/session.py | 1 + test/tls13.uts | 8 ++++---- 6 files changed, 18 insertions(+), 26 deletions(-) diff --git a/scapy/layers/tls/basefields.py b/scapy/layers/tls/basefields.py index 6c4968a975a..2428c32012b 100644 --- a/scapy/layers/tls/basefields.py +++ b/scapy/layers/tls/basefields.py @@ -18,9 +18,6 @@ 22: "handshake", 23: "application_data"} -# Types that will redirect to a TLS13 record if available -_tls_type_13 = [23] - _tls_version = {0x0002: "SSLv2", 0x0200: "SSLv2", 0x0300: "SSLv3", diff --git a/scapy/layers/tls/crypto/cipher_aead.py b/scapy/layers/tls/crypto/cipher_aead.py index 49919ab65c3..a5829d2aad9 100644 --- a/scapy/layers/tls/crypto/cipher_aead.py +++ b/scapy/layers/tls/crypto/cipher_aead.py @@ -342,7 +342,7 @@ def auth_decrypt(self, A, C, seq_num): """ C, mac = C[:-self.tag_len], C[-self.tag_len:] if False in six.itervalues(self.ready): - raise CipherError(C, mac) + raise CipherError(b"", C, mac) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce(seq_num) @@ -353,7 +353,7 @@ def auth_decrypt(self, A, C, seq_num): try: decryptor.finalize() except InvalidTag: - raise AEADTagError(P, mac) + raise AEADTagError(b"", P, mac) else: try: if (conf.crypto_valid_advanced and @@ -366,8 +366,8 @@ def auth_decrypt(self, A, C, seq_num): A += struct.pack("!H", len(C)) P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A) # noqa: E501 except InvalidTag: - raise AEADTagError(b"", mac) - return P, mac + raise AEADTagError(b"", b"", mac) + return b"", P, mac def snapshot(self): c = self.__class__(self.key, self.fixed_iv) diff --git a/scapy/layers/tls/record.py b/scapy/layers/tls/record.py index 4c2a9c2f6a4..5ed1393f46f 100644 --- a/scapy/layers/tls/record.py +++ b/scapy/layers/tls/record.py @@ -27,16 +27,13 @@ from scapy.layers.tls.basefields import (_TLSVersionField, _tls_version, _TLSIVField, _TLSMACField, _TLSPadField, _TLSPadLenField, - _TLSLengthField, _tls_type, - _tls_type_13) + _TLSLengthField, _tls_type) from scapy.layers.tls.crypto.pkcs1 import pkcs_i2osp from scapy.layers.tls.crypto.cipher_aead import AEADTagError from scapy.layers.tls.crypto.cipher_stream import Cipher_NULL from scapy.layers.tls.crypto.common import CipherError from scapy.layers.tls.crypto.h_mac import HMACError import scapy.modules.six as six -if conf.crypto_valid_advanced: - from scapy.layers.tls.crypto.cipher_aead import Cipher_CHACHA20_POLY1305 # Util @@ -285,12 +282,12 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 2: type_ = orb(_pkt[0]) version_ = orb(_pkt[1]) + s = kargs.get("tls_session", None) if (type_ not in _tls_type) or (version_ != 3): from scapy.layers.tls.record_sslv2 import SSLv2 return SSLv2 - elif type_ in _tls_type_13: - s = kargs.get("tls_session", None) - if s and _tls_version_check(s.tls_version, 0x0304): + elif s and _tls_version_check(s.tls_version, 0x0304): + if type_ == 23: if s.rcs and not isinstance(s.rcs.cipher, Cipher_NULL): from scapy.layers.tls.record_tls13 import TLS13 return TLS13 @@ -476,13 +473,8 @@ def pre_dissect(self, s): elif cipher_type == 'aead': # Authenticated encryption # crypto/cipher_aead.py prints a warning for integrity failure - if (conf.crypto_valid_advanced and - isinstance(self.tls_session.rcs.cipher, - Cipher_CHACHA20_POLY1305)): - iv = b"" - cfrag, mac = self._tls_auth_decrypt(hdr, efrag) - else: - iv, cfrag, mac = self._tls_auth_decrypt(hdr, efrag) + print(self.__class__) + iv, cfrag, mac = self._tls_auth_decrypt(hdr, efrag) decryption_success = True # see XXX above frag = self._tls_decompress(cfrag) diff --git a/scapy/layers/tls/record_tls13.py b/scapy/layers/tls/record_tls13.py index 93623150a3f..14b0997ed78 100644 --- a/scapy/layers/tls/record_tls13.py +++ b/scapy/layers/tls/record_tls13.py @@ -113,6 +113,8 @@ def _tls_auth_decrypt(self, s): read_seq_num = struct.pack("!Q", rcs.seq_num) rcs.seq_num += 1 try: + print(read_seq_num) + print(s) return rcs.cipher.auth_decrypt(b"", s, read_seq_num) except CipherError as e: return e.args @@ -134,7 +136,7 @@ def pre_dissect(self, s): else: msglen = struct.unpack('!H', s[3:5])[0] hdr, efrag, r = s[:5], s[5:5 + msglen], s[msglen + 5:] - frag, auth_tag = self._tls_auth_decrypt(efrag) + _, frag, auth_tag = self._tls_auth_decrypt(efrag) self.deciphered_len = len(frag) return hdr + frag + auth_tag + r diff --git a/scapy/layers/tls/session.py b/scapy/layers/tls/session.py index d64536b3211..1d30faf2249 100644 --- a/scapy/layers/tls/session.py +++ b/scapy/layers/tls/session.py @@ -72,6 +72,7 @@ def __init__(self, tls_version=0x0303): self.tls_version = tls_version + print(tls_version) # It is the user's responsibility to keep the record seq_num # under 2**64-1. If this value gets maxed out, the TLS class in diff --git a/test/tls13.uts b/test/tls13.uts index 3005aad5b01..c4071714068 100644 --- a/test/tls13.uts +++ b/test/tls13.uts @@ -21,7 +21,7 @@ from cryptography.hazmat.backends import default_backend def clean(s): return binascii.unhexlify(''.join(c for c in s if c.isalnum())) -= Dissect ClientHello : The client initiates a handshake with an X25519 +#= Dissect ClientHello : The client initiates a handshake with an X25519 clientHello1 = clean(""" 16 03 01 00 b4 01 00 00 b0 03 03 b0 @@ -37,7 +37,7 @@ clientHello1 = clean(""" """) t1 = TLS(clientHello1) -= Dissect ServerHello: The server however prefers P-256 [FIPS186] and sends a HelloRetryRequest +#= Dissect ServerHello: The server however prefers P-256 [FIPS186] and sends a HelloRetryRequest # Note: The HelloRetryRequest uses the same handshake message type as # a ServerHello and so is labeled as ServerHello here. @@ -55,7 +55,7 @@ helloRetryRequest = clean(""" """) t2 = TLS(helloRetryRequest, tls_session=t1.tls_session.mirror()) -= Dissect ClientHello again, this time using P-256 +#= Dissect ClientHello again, this time using P-256 secp256r1_client_privkey = clean(""" ab 54 73 46 7e 19 34 6c eb 0a 04 14 e4 @@ -89,7 +89,7 @@ clientHello2 = clean(""" 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 """) -t3 = TLS(clientHello2) +t3 = TLS(clientHello2, tls_session=t2.tls_session.mirror()) pubnum = t3.tls_session.tls13_client_pubshares["secp256r1"].public_numbers() privnum = EllipticCurvePrivateNumbers(pkcs_os2ip(secp256r1_client_privkey), pubnum) privkey = privnum.private_key(default_backend()) From 64257a481c6456cd22df7a3ba13f80ae15e976fa Mon Sep 17 00:00:00 2001 From: gpotter2 Date: Sat, 22 Jun 2019 11:43:16 +0200 Subject: [PATCH 5/8] Update cryptography methods & TLS 1.3 secrets --- scapy/layers/tls/crypto/cipher_aead.py | 1 + scapy/layers/tls/handshake.py | 5 ++++- scapy/layers/tls/keyexchange.py | 9 +++++---- scapy/layers/tls/keyexchange_tls13.py | 5 +++-- scapy/layers/tls/record.py | 4 +++- scapy/layers/tls/record_tls13.py | 7 ++++--- scapy/layers/tls/session.py | 25 ++++++++++++------------- test/tls.uts | 2 +- test/tls13.uts | 10 +++++----- 9 files changed, 38 insertions(+), 30 deletions(-) diff --git a/scapy/layers/tls/crypto/cipher_aead.py b/scapy/layers/tls/crypto/cipher_aead.py index a5829d2aad9..87b3c566ce1 100644 --- a/scapy/layers/tls/crypto/cipher_aead.py +++ b/scapy/layers/tls/crypto/cipher_aead.py @@ -340,6 +340,7 @@ def auth_decrypt(self, A, C, seq_num): responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. """ + C, mac = C[:-self.tag_len], C[-self.tag_len:] if False in six.itervalues(self.ready): raise CipherError(b"", C, mac) diff --git a/scapy/layers/tls/handshake.py b/scapy/layers/tls/handshake.py index 7110ece2c4d..d768079eadc 100644 --- a/scapy/layers/tls/handshake.py +++ b/scapy/layers/tls/handshake.py @@ -388,7 +388,6 @@ def tls_session_update(self, msg_str): s.server_random = (struct.pack('!I', self.gmt_unix_time) + self.random_bytes) - s.sid = self.sid # EXT process if self.ext: @@ -405,6 +404,10 @@ def tls_session_update(self, msg_str): is_tls13 = s.tls_version >= 0x0304 if is_tls13 and s.server_random == _TLS_RetryRequestMagic: self.name = "TLS 1.3 Handshake - Hello Retry Request" + # This isn't a real ServerHello. Don't process further + return + + s.sid = self.sid cs_cls = None if self.cipher: diff --git a/scapy/layers/tls/keyexchange.py b/scapy/layers/tls/keyexchange.py index 836008e44cc..fb0ac04e3ad 100644 --- a/scapy/layers/tls/keyexchange.py +++ b/scapy/layers/tls/keyexchange.py @@ -614,8 +614,8 @@ def register_pubkey(self): curve_name = _tls_named_curves[self.named_curve] curve = ec._CURVE_TYPES[curve_name]() - import_point = ec.EllipticCurvePublicNumbers.from_encoded_point - pubnum = import_point(curve, self.point) + import_point = ec.EllipticCurvePublicKey.from_encoded_point + pubnum = import_point(curve, self.point).public_numbers() s = self.tls_session s.server_kx_pubkey = pubnum.public_key(default_backend()) @@ -833,8 +833,9 @@ def post_dissection(self, m): # if there are kx params and keys, we assume the crypto library is ok if s.client_kx_ecdh_params: - import_point = ec.EllipticCurvePublicNumbers.from_encoded_point - pub_num = import_point(s.client_kx_ecdh_params, self.ecdh_Yc) + import_point = ec.EllipticCurvePublicKey.from_encoded_point + pub_key = import_point(s.client_kx_ecdh_params, self.ecdh_Yc) + pub_num = pub_key.public_numbers() s.client_kx_pubkey = pub_num.public_key(default_backend()) if s.server_kx_privkey and s.client_kx_pubkey: diff --git a/scapy/layers/tls/keyexchange_tls13.py b/scapy/layers/tls/keyexchange_tls13.py index 934563679c0..934da5c6cfd 100644 --- a/scapy/layers/tls/keyexchange_tls13.py +++ b/scapy/layers/tls/keyexchange_tls13.py @@ -119,8 +119,9 @@ def register_pubkey(self): self.pubkey = import_point(self.key_exchange) elif _tls_named_curves[self.group] != "x448": curve = ec._CURVE_TYPES[_tls_named_curves[self.group]]() - import_point = ec.EllipticCurvePublicNumbers.from_encoded_point - public_numbers = import_point(curve, self.key_exchange) + import_point = ec.EllipticCurvePublicKey.from_encoded_point + public_key = import_point(curve, self.key_exchange) + public_numbers = public_key.public_numbers() self.pubkey = public_numbers.public_key(default_backend()) def post_dissection(self, r): diff --git a/scapy/layers/tls/record.py b/scapy/layers/tls/record.py index 5ed1393f46f..b9f57086537 100644 --- a/scapy/layers/tls/record.py +++ b/scapy/layers/tls/record.py @@ -287,6 +287,8 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): from scapy.layers.tls.record_sslv2 import SSLv2 return SSLv2 elif s and _tls_version_check(s.tls_version, 0x0304): + # "The outer opaque_type field of a TLSCiphertext record + # is always set to the value 23" if type_ == 23: if s.rcs and not isinstance(s.rcs.cipher, Cipher_NULL): from scapy.layers.tls.record_tls13 import TLS13 @@ -387,6 +389,7 @@ def pre_dissect(self, s): raise Exception("Invalid record: header is too short.") msglen = struct.unpack('!H', s[3:5])[0] + hdr, efrag, r = s[:5], s[5:5 + msglen], s[msglen + 5:] iv = mac = pad = b"" @@ -473,7 +476,6 @@ def pre_dissect(self, s): elif cipher_type == 'aead': # Authenticated encryption # crypto/cipher_aead.py prints a warning for integrity failure - print(self.__class__) iv, cfrag, mac = self._tls_auth_decrypt(hdr, efrag) decryption_success = True # see XXX above diff --git a/scapy/layers/tls/record_tls13.py b/scapy/layers/tls/record_tls13.py index 14b0997ed78..db89233a5cc 100644 --- a/scapy/layers/tls/record_tls13.py +++ b/scapy/layers/tls/record_tls13.py @@ -113,14 +113,15 @@ def _tls_auth_decrypt(self, s): read_seq_num = struct.pack("!Q", rcs.seq_num) rcs.seq_num += 1 try: - print(read_seq_num) - print(s) return rcs.cipher.auth_decrypt(b"", s, read_seq_num) except CipherError as e: return e.args except AEADTagError as e: pkt_info = self.firstlayer().summary() - log_runtime.info("TLS: record integrity check failed [%s]", pkt_info) # noqa: E501 + raise + log_runtime.info( + "TLS13: record integrity check failed [%s]", pkt_info + ) return e.args def pre_dissect(self, s): diff --git a/scapy/layers/tls/session.py b/scapy/layers/tls/session.py index 1d30faf2249..d70e0355448 100644 --- a/scapy/layers/tls/session.py +++ b/scapy/layers/tls/session.py @@ -72,7 +72,6 @@ def __init__(self, tls_version=0x0303): self.tls_version = tls_version - print(tls_version) # It is the user's responsibility to keep the record seq_num # under 2**64-1. If this value gets maxed out, the TLS class in @@ -589,8 +588,8 @@ def compute_tls13_early_secrets(self): self.tls13_psk_secret) bk = hkdf.derive_secret(self.tls13_early_secret, - b"external psk binder key", - # "resumption psk binder key", + b"ext binder", + # "res binder", b"") self.tls13_derived_secrets["binder_key"] = bk @@ -599,12 +598,12 @@ def compute_tls13_early_secrets(self): return cets = hkdf.derive_secret(self.tls13_early_secret, - b"client early traffic secret", + b"c e traffic", b"".join(self.handshake_messages)) self.tls13_derived_secrets["client_early_traffic_secret"] = cets ees = hkdf.derive_secret(self.tls13_early_secret, - b"early exporter master secret", + b"e exp master", b"".join(self.handshake_messages)) self.tls13_derived_secrets["early_exporter_secret"] = ees @@ -627,12 +626,12 @@ def compute_tls13_handshake_secrets(self): self.tls13_dhe_secret) chts = hkdf.derive_secret(self.tls13_handshake_secret, - b"client handshake traffic secret", + b"c hs traffic", b"".join(self.handshake_messages)) self.tls13_derived_secrets["client_handshake_traffic_secret"] = chts shts = hkdf.derive_secret(self.tls13_handshake_secret, - b"server handshake traffic secret", + b"s hs traffic", b"".join(self.handshake_messages)) self.tls13_derived_secrets["server_handshake_traffic_secret"] = shts @@ -654,17 +653,17 @@ def compute_tls13_traffic_secrets(self): None) cts0 = hkdf.derive_secret(self.tls13_master_secret, - b"client application traffic secret", + b"c ap traffic", b"".join(self.handshake_messages)) self.tls13_derived_secrets["client_traffic_secrets"] = [cts0] sts0 = hkdf.derive_secret(self.tls13_master_secret, - b"server application traffic secret", + b"s ap traffic", b"".join(self.handshake_messages)) self.tls13_derived_secrets["server_traffic_secrets"] = [sts0] es = hkdf.derive_secret(self.tls13_master_secret, - b"exporter master secret", + b"exp master", b"".join(self.handshake_messages)) self.tls13_derived_secrets["exporter_secret"] = es @@ -714,7 +713,7 @@ def compute_tls13_resumption_secret(self): elif self.connection_end == "client": hkdf = self.pwcs.hkdf rs = hkdf.derive_secret(self.tls13_master_secret, - b"resumption master secret", + b"res master", b"".join(self.handshake_messages)) self.tls13_derived_secrets["resumption_secret"] = rs @@ -727,10 +726,10 @@ def compute_tls13_next_traffic_secrets(self): cts = self.tls13_derived_secrets["client_traffic_secrets"] ctsN = cts[-1] - ctsN_1 = hkdf.expand_label(ctsN, "application traffic secret", "", hl) + ctsN_1 = hkdf.expand_label(ctsN, "traffic upd", "", hl) cts.append(ctsN_1) - stsN_1 = hkdf.expand_label(ctsN, "application traffic secret", "", hl) + stsN_1 = hkdf.expand_label(ctsN, "traffic upd", "", hl) cts.append(stsN_1) if self.connection_end == "server": diff --git a/test/tls.uts b/test/tls.uts index e9a8c98d11f..149273865e7 100644 --- a/test/tls.uts +++ b/test/tls.uts @@ -713,7 +713,7 @@ def _all_chacha20poly1305_tests(): ciphers = [] for t in [_chacha20poly1305_test_1]: c = Cipher_CHACHA20_POLY1305_TLS13(key=t.k, fixed_iv=t.n) - tmp1 = c.auth_decrypt(t.a, t.ct + t.tag, b"\0"*8) == (t.p, t.tag) + tmp1 = c.auth_decrypt(t.a, t.ct + t.tag, b"\0"*8) == (b"", t.p, t.tag) tmp2 = c.auth_encrypt(t.p, t.a, b"\0"*8) == t.ct + t.tag res = res and tmp1 and tmp2 return res diff --git a/test/tls13.uts b/test/tls13.uts index c4071714068..ce01c555b32 100644 --- a/test/tls13.uts +++ b/test/tls13.uts @@ -7,9 +7,9 @@ # /!\ These tests will not catch our 'INTEGRITY CHECK FAILED's. /!\ # We deem the knowledge of the plaintext sufficient for passing... -# https://tools.ietf.org/html/draft-ietf-tls-tls13-vectors-07#section-5 +# https://tools.ietf.org/html/rfc8448#section-5 -+ Reading TLS 1.3 test session (vectors 5 from draft-ietf-tls-tls13-vectors-07) ++ Reading TLS 1.3 test session (vectors 5 from rfc8448) ~ crypto = Load utils @@ -21,7 +21,7 @@ from cryptography.hazmat.backends import default_backend def clean(s): return binascii.unhexlify(''.join(c for c in s if c.isalnum())) -#= Dissect ClientHello : The client initiates a handshake with an X25519 += Dissect ClientHello : The client initiates a handshake with an X25519 clientHello1 = clean(""" 16 03 01 00 b4 01 00 00 b0 03 03 b0 @@ -37,7 +37,7 @@ clientHello1 = clean(""" """) t1 = TLS(clientHello1) -#= Dissect ServerHello: The server however prefers P-256 [FIPS186] and sends a HelloRetryRequest += Dissect ServerHello: The server however prefers P-256 [FIPS186] and sends a HelloRetryRequest # Note: The HelloRetryRequest uses the same handshake message type as # a ServerHello and so is labeled as ServerHello here. @@ -55,7 +55,7 @@ helloRetryRequest = clean(""" """) t2 = TLS(helloRetryRequest, tls_session=t1.tls_session.mirror()) -#= Dissect ClientHello again, this time using P-256 += Dissect ClientHello again, this time using P-256 secp256r1_client_privkey = clean(""" ab 54 73 46 7e 19 34 6c eb 0a 04 14 e4 From af242c4c29efee3d08a6ad07faa850cd494b1c61 Mon Sep 17 00:00:00 2001 From: gpotter2 Date: Sat, 22 Jun 2019 15:07:18 +0200 Subject: [PATCH 6/8] Remove unused HelloRetryRequest --- scapy/layers/tls/handshake.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/scapy/layers/tls/handshake.py b/scapy/layers/tls/handshake.py index d768079eadc..b7ecf9a1413 100644 --- a/scapy/layers/tls/handshake.py +++ b/scapy/layers/tls/handshake.py @@ -455,20 +455,6 @@ def tls_session_update(self, msg_str): tls_version=s.tls_version) -############################################################################### -# HelloRetryRequest # -############################################################################### - -class TLSHelloRetryRequest(_TLSHandshake): - name = "TLS 1.3 Handshake - Hello Retry Request" - fields_desc = [ByteEnumField("msgtype", 6, _tls_handshake_type), - ThreeBytesField("msglen", None), - _TLSVersionField("version", None, _tls_version), - _ExtensionsLenField("extlen", None, length_of="ext"), - _ExtensionsField("ext", None, - length_from=lambda pkt: pkt.msglen - 4)] - - ############################################################################### # EncryptedExtensions # ############################################################################### From 43d8f6fc4317073680f0c8750ba018cbcc805e21 Mon Sep 17 00:00:00 2001 From: gpotter2 Date: Sun, 23 Jun 2019 09:54:03 +0200 Subject: [PATCH 7/8] Update vectors according to Errata 5720 --- test/tls13.uts | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/test/tls13.uts b/test/tls13.uts index ce01c555b32..8c7b58b2685 100644 --- a/test/tls13.uts +++ b/test/tls13.uts @@ -9,8 +9,7 @@ # https://tools.ietf.org/html/rfc8448#section-5 -+ Reading TLS 1.3 test session (vectors 5 from rfc8448) -~ crypto ++ Init phase = Load utils @@ -21,6 +20,9 @@ from cryptography.hazmat.backends import default_backend def clean(s): return binascii.unhexlify(''.join(c for c in s if c.isalnum())) ++ Reading TLS 1.3 test session (vectors 5 from rfc8448) +~ crypto + = Dissect ClientHello : The client initiates a handshake with an X25519 clientHello1 = clean(""" @@ -31,9 +33,8 @@ clientHello1 = clean(""" 00 00 0a 00 08 00 06 00 1d 00 17 00 18 00 33 00 26 00 24 00 1d 00 20 e8 e8 e3 f3 b9 3a 25 ed 97 a1 4a 7d ca cb 8a 27 2c 62 88 e5 85 c6 48 4d 05 26 2f ca d0 62 ad 1f 00 2b 00 03 02 03 04 00 - 0d 00 20 00 1e 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 - 05 01 06 01 02 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 - 1c 00 02 40 01 + 0d 00 18 00 16 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 + 05 01 06 01 02 01 00 2d 00 02 01 01 00 1c 00 02 40 01 """) t1 = TLS(clientHello1) @@ -70,9 +71,9 @@ clientHello2 = clean(""" 00 41 04 a6 da 73 92 ec 59 1e 17 ab fd 53 59 64 b9 98 94 d1 3b ef b2 21 b3 de f2 eb e3 83 0e ac 8f 01 51 81 26 77 c4 d6 d2 23 7e 85 cf 01 d6 91 0c fb 83 95 4e 76 ba 73 52 83 05 34 15 98 97 - e8 06 57 80 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 - 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 - 02 06 02 02 02 00 2c 00 74 00 72 71 dc d0 4b b8 8b c3 18 91 19 + e8 06 57 80 00 2b 00 03 02 03 04 00 0d 00 18 00 16 04 03 05 03 + 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 00 2c 00 + 74 00 72 71 dc d0 4b b8 8b c3 18 91 19 39 8a 00 00 00 00 ee fa fc 76 c1 46 b8 23 b0 96 f8 aa ca d3 65 dd 00 30 95 3f 4e df 62 56 36 e5 f2 1b b2 e2 3f cc 65 4b 1b 5b 40 31 8d 10 d1 37 ab cb b8 75 74 e3 6e 8a 1f 02 5f 7d fa 5d 6e @@ -182,7 +183,7 @@ assert(isinstance(alert, TLSAlert)) alert.level == 1 and alert.descr == 0 -+ Reading TLS 1.3 test session (vectors 3 from draft-ietf-tls-tls13-vectors-00) ++ Reading TLS 1.3 test session (vectors 3 from rfc8448) ~ crypto_advanced = Dissect ClientHello handshake message @@ -201,12 +202,12 @@ clientHello = clean(""" 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d - 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e + 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 18 00 16 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 - 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 + 01 00 2d 00 02 01 01 00 1c 00 02 40 01 """) t1 = TLS(clientHello) -privkey = X25519PrivateKey._from_private_bytes(x25519_client_privkey) +privkey = X25519PrivateKey.from_private_bytes(x25519_client_privkey) t1.tls_session.tls13_client_privshares["x25519"] = privkey = Dissect ServerHello handshake message From f9b440e31a2b0c6a593c213a5396a5724fde8f7b Mon Sep 17 00:00:00 2001 From: gpotter2 Date: Sun, 23 Jun 2019 11:39:51 +0200 Subject: [PATCH 8/8] Add TLS1.3 DEBUG tests --- test/tls13_debug.uts | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 test/tls13_debug.uts diff --git a/test/tls13_debug.uts b/test/tls13_debug.uts new file mode 100644 index 00000000000..cc422d154cc --- /dev/null +++ b/test/tls13_debug.uts @@ -0,0 +1,44 @@ +% TLS 1.3 session - DEBUG + ++ Debug - use data of https://tls13.ulfheim.net/ +~ crypto +* So that it's easy to see what goes wrong + += Run tests + +import binascii +from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateNumbers +from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey +from cryptography.hazmat.backends import default_backend + +def clean(s): + return binascii.unhexlify(''.join(c for c in s if c.isalnum())) + +privatekey_client = hex_bytes("202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f") + +clientHello = TLS( + clean("""16 03 01 00 ca 01 00 00 c6 03 03 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 00 06 13 01 13 02 13 03 01 00 00 77 00 00 00 18 00 16 00 00 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00 0a 00 08 00 06 00 1d 00 17 00 18 00 0d 00 14 00 12 04 03 08 04 04 01 05 03 08 05 05 01 08 06 06 01 02 01 00 33 00 26 00 24 00 1d 00 20 35 80 72 d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54 00 2d 00 02 01 01 00 2b 00 03 02 03 04 """) +) + +privkey = X25519PrivateKey.from_private_bytes(privatekey_client) +clientHello.tls_session.tls13_client_privshares["x25519"] = privkey + +# ServerHello + +privatekey_server = hex_bytes("909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf") + +tls_session=clientHello.tls_session.mirror() +privkey = X25519PrivateKey.from_private_bytes(privatekey_server) +tls_session.tls13_server_privshare["x25519"] = privkey + +serverHello = TLS( + clean("""16 03 03 00 7a 02 00 00 76 03 03 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 13 01 00 00 2e 00 33 00 24 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98 28 80 b6 15 00 2b 00 02 03 04 """), + tls_session=tls_session +) + +# Server CHange Cipher Spec + +serverChangeCipherSpec = TLS( + clean("14 03 03 00 01 01 "), + tls_session=tls_session +) \ No newline at end of file