def compute_tls13_early_secrets(self, external=False): """ This function computes the Early Secret, the binder_key, the client_early_traffic_secret and the early_exporter_master_secret (See RFC8446, section 7.1). The parameter external is used for the computation of the binder_key: - For external PSK provisioned outside out of TLS, the parameter external must be True. - For resumption PSK, the parameter external must be False. If no argument is specified, the label "res binder" will be used by default. Ciphers key and IV are updated accordingly for 0-RTT data. self.handshake_messages should be ClientHello only. """ # if no hash algorithm is set, default to SHA-256 if self.prcs and self.prcs.hkdf: hkdf = self.prcs.hkdf elif self.pwcs and self.pwcs.hkdf: hkdf = self.pwcs.hkdf else: hkdf = TLS13_HKDF("sha256") if self.tls13_early_secret is None: self.tls13_early_secret = hkdf.extract(None, self.tls13_psk_secret) if "binder_key" not in self.tls13_derived_secrets: if external: bk = hkdf.derive_secret(self.tls13_early_secret, b"ext binder", b"") else: bk = hkdf.derive_secret(self.tls13_early_secret, b"res binder", b"") self.tls13_derived_secrets["binder_key"] = bk cets = hkdf.derive_secret(self.tls13_early_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"e exp master", b"".join(self.handshake_messages)) self.tls13_derived_secrets["early_exporter_secret"] = ees if self.connection_end == "server": if self.prcs: self.prcs.tls13_derive_keys(cets) elif self.connection_end == "client": if self.pwcs: self.pwcs.tls13_derive_keys(cets)
def tls13_should_add_ClientHello_Retry(self): s = self.cur_session s.tls13_retry = True # we have to use the legacy, plaintext TLS record here self.add_record(is_tls13=False) # We retrieve the group to be used and the selected version from the # previous message hrr = s.handshake_messages_parsed[-1] if isinstance(hrr, TLS13HelloRetryRequest): pass ciphersuite = hrr.cipher if hrr.ext: for e in hrr.ext: if isinstance(e, TLS_Ext_KeyShare_HRR): selected_group = e.selected_group if isinstance(e, TLS_Ext_SupportedVersion_SH): selected_version = e.version if not selected_group or not selected_version: raise self.CLOSE_NOTIFY() ext = [] ext += TLS_Ext_SupportedVersion_CH( versions=[_tls_version[selected_version]]) # noqa: E501 if s.tls13_psk_secret: if self.tls13_psk_mode == "psk_dhe_ke": ext += TLS_Ext_PSKKeyExchangeModes(kxmodes="psk_dhe_ke"), ext += TLS_Ext_SupportedGroups( groups=[_tls_named_groups[selected_group]]) # noqa: E501 ext += TLS_Ext_KeyShare_CH(client_shares=[ KeyShareEntry(group=selected_group) ]) # noqa: E501 else: ext += TLS_Ext_PSKKeyExchangeModes(kxmodes="psk_ke") hkdf = TLS13_HKDF("sha256") hash_len = hkdf.hash.digest_size psk_id = PSKIdentity(identity='Client_identity') psk_binder_entry = PSKBinderEntry(binder_len=hash_len, binder=b"\x00" * hash_len) ext += TLS_Ext_PreSharedKey_CH(identities=[psk_id], binders=[psk_binder_entry]) else: ext += TLS_Ext_SupportedGroups( groups=[_tls_named_groups[selected_group]]) # noqa: E501 ext += TLS_Ext_KeyShare_CH(client_shares=[ KeyShareEntry(group=selected_group) ]) # noqa: E501 ext += TLS_Ext_SignatureAlgorithms(sig_algs=["sha256+rsaepss"]) p = TLS13ClientHello(ciphers=ciphersuite, ext=ext) self.add_msg(p) raise self.TLS13_ADDED_CLIENTHELLO()
def __init__(self, connection_end="server", read_or_write="read", seq_num=0, compression_alg=Comp_NULL, ciphersuite=None, tls_version=0x0303): self.tls_version = 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 # record.py will crash when trying to encode it with struct.pack(). self.seq_num = seq_num self.connection_end = connection_end self.row = read_or_write if ciphersuite is None: from scapy.layers.tls.crypto.suites import TLS_NULL_WITH_NULL_NULL ciphersuite = TLS_NULL_WITH_NULL_NULL self.ciphersuite = ciphersuite(tls_version=tls_version) if not self.ciphersuite.usable: warning( "TLS ciphersuite not usable. Is the cryptography Python module installed ?" ) # noqa: E501 return self.compression = compression_alg() self.key_exchange = ciphersuite.kx_alg() self.cipher = ciphersuite.cipher_alg() self.hash = ciphersuite.hash_alg() if tls_version > 0x0200: if ciphersuite.cipher_alg.type == "aead": self.hmac = None self.mac_len = self.cipher.tag_len else: self.hmac = ciphersuite.hmac_alg() self.mac_len = self.hmac.hmac_len else: self.hmac = ciphersuite.hmac_alg() # should be Hmac_NULL self.mac_len = self.hash.hash_len if tls_version >= 0x0304: self.hkdf = TLS13_HKDF(self.hash.name.lower()) else: self.prf = PRF(ciphersuite.hash_alg.name, tls_version)
def tls13_should_add_ClientHello(self): # we have to use the legacy, plaintext TLS record here supported_groups = ["secp256r1", "secp384r1"] if conf.crypto_valid_advanced: supported_groups.append("x25519") self.add_record(is_tls13=False) if self.client_hello: p = self.client_hello else: if self.ciphersuite is None: c = 0x1301 else: c = self.ciphersuite p = TLS13ClientHello(ciphers=c) ext = [] ext += TLS_Ext_SupportedVersion_CH(versions=["TLS 1.3"]) if self.cur_session.tls13_psk_secret: if self.tls13_psk_mode == "psk_dhe_ke": ext += TLS_Ext_PSKKeyExchangeModes(kxmodes="psk_dhe_ke") ext += TLS_Ext_SupportedGroups(groups=supported_groups) ext += TLS_Ext_KeyShare_CH( client_shares=[KeyShareEntry(group=self.curve)]) else: ext += TLS_Ext_PSKKeyExchangeModes(kxmodes="psk_ke") # RFC844, section 4.2.11. # "The "pre_shared_key" extension MUST be the last extension # in the ClientHello " hkdf = TLS13_HKDF("sha256") hash_len = hkdf.hash.digest_size psk_id = PSKIdentity(identity='Client_identity') # XXX see how to not pass binder as argument psk_binder_entry = PSKBinderEntry(binder_len=hash_len, binder=b"\x00" * hash_len) ext += TLS_Ext_PreSharedKey_CH(identities=[psk_id], binders=[psk_binder_entry]) else: ext += TLS_Ext_SupportedGroups(groups=supported_groups) ext += TLS_Ext_KeyShare_CH( client_shares=[KeyShareEntry(group=self.curve)]) ext += TLS_Ext_SignatureAlgorithms( sig_algs=["sha256+rsaepss", "sha256+rsa"]) p.ext = ext self.add_msg(p) raise self.TLS13_ADDED_CLIENTHELLO()
def tls13_should_add_ClientHello(self): # we have to use the legacy, plaintext TLS record here supported_groups = ["secp256r1", "secp384r1"] if conf.crypto_valid_advanced: supported_groups.append("x25519") self.add_record(is_tls13=False) if self.client_hello: p = self.client_hello else: if self.ciphersuite is None: c = 0x1301 else: c = self.ciphersuite p = TLS13ClientHello(ciphers=c) ext = [] ext += TLS_Ext_SupportedVersion_CH(versions=["TLS 1.3"]) s = self.cur_session if s.tls13_psk_secret: # Check if DHE is need (both for out of band and resumption PSK) if self.tls13_psk_mode == "psk_dhe_ke": ext += TLS_Ext_PSKKeyExchangeModes(kxmodes="psk_dhe_ke") ext += TLS_Ext_SupportedGroups(groups=supported_groups) ext += TLS_Ext_KeyShare_CH( client_shares=[KeyShareEntry(group=self.curve)]) else: ext += TLS_Ext_PSKKeyExchangeModes(kxmodes="psk_ke") # RFC844, section 4.2.11. # "The "pre_shared_key" extension MUST be the last extension # in the ClientHello " # Compute the pre_shared_key extension for resumption PSK if s.client_session_ticket: cs_cls = _tls_cipher_suites_cls[ s.tls13_ticket_ciphersuite] # noqa: E501 hkdf = TLS13_HKDF(cs_cls.hash_alg.name.lower()) hash_len = hkdf.hash.digest_size # We compute the client's view of the age of the ticket (ie # the time since the receipt of the ticket) in ms agems = int((time.time() - s.client_ticket_age) * 1000) # Then we compute the obfuscated version of the ticket age # by adding the "ticket_age_add" value included in the # ticket (modulo 2^32) obfuscated_age = ((agems + s.client_session_ticket_age_add) & 0xffffffff) psk_id = PSKIdentity(identity=s.client_session_ticket, obfuscated_ticket_age=obfuscated_age) psk_binder_entry = PSKBinderEntry(binder_len=hash_len, binder=b"\x00" * hash_len) ext += TLS_Ext_PreSharedKey_CH(identities=[psk_id], binders=[psk_binder_entry]) else: # Compute the pre_shared_key extension for out of band PSK # (SHA256 is used as default hash function for HKDF for out # of band PSK) hkdf = TLS13_HKDF("sha256") hash_len = hkdf.hash.digest_size psk_id = PSKIdentity(identity='Client_identity') # XXX see how to not pass binder as argument psk_binder_entry = PSKBinderEntry(binder_len=hash_len, binder=b"\x00" * hash_len) ext += TLS_Ext_PreSharedKey_CH(identities=[psk_id], binders=[psk_binder_entry]) else: ext += TLS_Ext_SupportedGroups(groups=supported_groups) ext += TLS_Ext_KeyShare_CH( client_shares=[KeyShareEntry(group=self.curve)]) ext += TLS_Ext_SignatureAlgorithms( sig_algs=["sha256+rsaepss", "sha256+rsa"]) p.ext = ext self.add_msg(p) raise self.TLS13_ADDED_CLIENTHELLO()
def INIT_TLS_SESSION(self): self.cur_session = tlsSession(connection_end="client") s = self.cur_session s.client_certs = self.mycert s.client_key = self.mykey v = self.advertised_tls_version if v: s.advertised_tls_version = v else: default_version = s.advertised_tls_version self.advertised_tls_version = default_version if s.advertised_tls_version >= 0x0304: # For out of band PSK, the PSK is given as an argument # to the automaton if self.tls13_psk_secret: s.tls13_psk_secret = binascii.unhexlify(self.tls13_psk_secret) # For resumed PSK, the PSK is computed from if self.session_ticket_file_in: with open(self.session_ticket_file_in, 'rb') as f: resumed_ciphersuite_len = struct.unpack("B", f.read(1))[0] s.tls13_ticket_ciphersuite = \ struct.unpack("!H", f.read(resumed_ciphersuite_len))[0] ticket_nonce_len = struct.unpack("B", f.read(1))[0] # XXX add client_session_nonce member in tlsSession s.client_session_nonce = f.read(ticket_nonce_len) client_ticket_age_len = struct.unpack("!H", f.read(2))[0] tmp = f.read(client_ticket_age_len) s.client_ticket_age = struct.unpack("!I", tmp)[0] client_ticket_age_add_len = struct.unpack("!H", f.read(2))[0] tmp = f.read(client_ticket_age_add_len) s.client_session_ticket_age_add = struct.unpack("!I", tmp)[0] ticket_len = struct.unpack("!H", f.read(2))[0] s.client_session_ticket = f.read(ticket_len) if self.resumption_master_secret: if s.tls13_ticket_ciphersuite not in _tls_cipher_suites_cls: # noqa: E501 warning("Unknown cipher suite %d" % s.tls13_ticket_ciphersuite) # noqa: E501 # we do not try to set a default nor stop the execution else: cs_cls = _tls_cipher_suites_cls[ s.tls13_ticket_ciphersuite] # noqa: E501 hkdf = TLS13_HKDF(cs_cls.hash_alg.name.lower()) hash_len = hkdf.hash.digest_size s.tls13_psk_secret = hkdf.expand_label( binascii.unhexlify( self.resumption_master_secret), # noqa: E501 b"resumption", s.client_session_nonce, # noqa: E501 hash_len) raise self.CONNECT()
def tls13_should_add_ClientHello_Retry(self): s = self.cur_session s.tls13_retry = True # we have to use the legacy, plaintext TLS record here self.add_record(is_tls13=False) # We retrieve the group to be used and the selected version from the # previous message hrr = s.handshake_messages_parsed[-1] if isinstance(hrr, TLS13HelloRetryRequest): pass ciphersuite = hrr.cipher if hrr.ext: for e in hrr.ext: if isinstance(e, TLS_Ext_KeyShare_HRR): selected_group = e.selected_group if isinstance(e, TLS_Ext_SupportedVersion_SH): selected_version = e.version if not selected_group or not selected_version: raise self.CLOSE_NOTIFY() ext = [] ext += TLS_Ext_SupportedVersion_CH( versions=[_tls_version[selected_version]]) # noqa: E501 if s.tls13_psk_secret: if self.tls13_psk_mode == "psk_dhe_ke": ext += TLS_Ext_PSKKeyExchangeModes(kxmodes="psk_dhe_ke"), ext += TLS_Ext_SupportedGroups( groups=[_tls_named_groups[selected_group]]) # noqa: E501 ext += TLS_Ext_KeyShare_CH(client_shares=[ KeyShareEntry(group=selected_group) ]) # noqa: E501 else: ext += TLS_Ext_PSKKeyExchangeModes(kxmodes="psk_ke") if s.client_session_ticket: # XXX Retrieve parameters from first ClientHello... cs_cls = _tls_cipher_suites_cls[s.tls13_ticket_ciphersuite] hkdf = TLS13_HKDF(cs_cls.hash_alg.name.lower()) hash_len = hkdf.hash.digest_size # We compute the client's view of the age of the ticket (ie # the time since the receipt of the ticket) in ms agems = int((time.time() - s.client_ticket_age) * 1000) # Then we compute the obfuscated version of the ticket age by # adding the "ticket_age_add" value included in the ticket # (modulo 2^32) obfuscated_age = ((agems + s.client_session_ticket_age_add) & 0xffffffff) psk_id = PSKIdentity(identity=s.client_session_ticket, obfuscated_ticket_age=obfuscated_age) psk_binder_entry = PSKBinderEntry(binder_len=hash_len, binder=b"\x00" * hash_len) ext += TLS_Ext_PreSharedKey_CH(identities=[psk_id], binders=[psk_binder_entry]) else: hkdf = TLS13_HKDF("sha256") hash_len = hkdf.hash.digest_size psk_id = PSKIdentity(identity='Client_identity') psk_binder_entry = PSKBinderEntry(binder_len=hash_len, binder=b"\x00" * hash_len) ext += TLS_Ext_PreSharedKey_CH(identities=[psk_id], binders=[psk_binder_entry]) else: ext += TLS_Ext_SupportedGroups( groups=[_tls_named_groups[selected_group]]) # noqa: E501 ext += TLS_Ext_KeyShare_CH(client_shares=[ KeyShareEntry(group=selected_group) ]) # noqa: E501 ext += TLS_Ext_SignatureAlgorithms(sig_algs=["sha256+rsaepss"]) p = TLS13ClientHello(ciphers=ciphersuite, ext=ext) self.add_msg(p) raise self.TLS13_ADDED_CLIENTHELLO()