def should_check_ciphersuites(self): """ We extract cipher suites candidates from the client's proposition. """ if isinstance(self.mykey, PrivKeyRSA): kx = "RSA" elif isinstance(self.mykey, PrivKeyECDSA): kx = "ECDSA" if get_usable_ciphersuites(self.cur_pkt.ciphers, kx): return raise self.NO_USABLE_CIPHERSUITE()
def HANDLED_CLIENTHELLO(self): """ We extract cipher suites candidates from the client's proposition. """ if isinstance(self.mykey, PrivKeyRSA): kx = "RSA" elif isinstance(self.mykey, PrivKeyECDSA): kx = "ECDSA" if get_usable_ciphersuites(self.cur_pkt.ciphers, kx): raise self.PREPARE_SERVERFLIGHT1() raise self.NO_USABLE_CIPHERSUITE()
def should_REPLY_TO_CH(self): """ XXX Several enhancements needed here. Selecting a cipher suite should be no trouble as we already caught the None case previously. However, regarding the protocol version, we might want to try resending a ClientHello when the advertised version is not deemed satisfying. Then, the sending of ServerHello, Certificate, ServerKeyExchange and ServerHelloDone should be split into multiple states, in order for the user to overload only the ones he's interested in. Also, we do not manage extensions at all. """ if isinstance(self.mykey, PrivKeyRSA): kx = "RSA" elif isinstance(self.mykey, PrivKeyECDSA): kx = "ECDSA" usable_suites = get_usable_ciphersuites(self.cur_pkt.ciphers, kx) c = usable_suites[0] if self.preferred_ciphersuite in usable_suites: c = self.preferred_ciphersuite comp = 0 if self.cur_pkt.comp and 1 in self.cur_pkt.comp: comp = 1 self.cur_session.advertised_tls_version = self.cur_pkt.version self.cur_session.tls_version = self.cur_pkt.version #XXX there should be some checks on this version from the ClientHello v = self.cur_session.tls_version print "\nVersion: " + _tls_version[v] print "Cipher suite: " + _tls_cipher_suites[c] self.cur_pkt = TLS(tls_session=self.cur_session, msg=[]) p = TLSServerHello(cipher=c, comp=[comp]) self.cur_pkt.msg.append(p) p = TLSCertificate(certs=self.cur_session.server_certs) self.cur_pkt.msg.append(p) if not _tls_cipher_suites_cls[c].kx_alg.no_ske: p = TLSServerKeyExchange() self.cur_pkt.msg.append(p) p = TLSServerHelloDone() self.cur_pkt.msg.append(p) self.socket.send(str(self.cur_pkt)) self.cur_pkt = None raise self.SENT_SH()
def tls13_should_add_ServerHello(self): psk_identity = None psk_key_exchange_mode = None obfuscated_age = None # XXX check ClientHello extensions... for m in reversed(self.cur_session.handshake_messages_parsed): if isinstance(m, (TLS13ClientHello, TLSClientHello)): for e in m.ext: if isinstance(e, TLS_Ext_PreSharedKey_CH): psk_identity = e.identities[0].identity obfuscated_age = e.identities[0].obfuscated_ticket_age # binder = e.binders[0].binder # For out-of-bound PSK, obfuscated_ticket_age should be # 0. We use this field to distinguish between out-of- # bound PSK and resumed PSK is_out_of_band_psk = (obfuscated_age == 0) if isinstance(e, TLS_Ext_PSKKeyExchangeModes): psk_key_exchange_mode = e.kxmodes[0] if isinstance(self.mykey, PrivKeyRSA): kx = "RSA" elif isinstance(self.mykey, PrivKeyECDSA): kx = "ECDSA" usable_suites = get_usable_ciphersuites(self.cur_pkt.ciphers, kx) c = usable_suites[0] group = next(iter(self.cur_session.tls13_client_pubshares)) ext = [TLS_Ext_SupportedVersion_SH(version="TLS 1.3")] if (psk_identity and obfuscated_age and psk_key_exchange_mode): s = self.cur_session if is_out_of_band_psk: # Handshake with external PSK authentication # XXX test that self.psk_secret is set s.tls13_psk_secret = binascii.unhexlify(self.psk_secret) # 0: "psk_ke" # 1: "psk_dhe_ke" if psk_key_exchange_mode == 1: server_kse = KeyShareEntry(group=group) ext += TLS_Ext_KeyShare_SH(server_share=server_kse) ext += TLS_Ext_PreSharedKey_SH(selected_identity=0) else: # Standard Handshake ext += TLS_Ext_KeyShare_SH(server_share=KeyShareEntry(group=group)) if self.cur_session.sid is not None: p = TLS13ServerHello(cipher=c, sid=self.cur_session.sid, ext=ext) else: p = TLS13ServerHello(cipher=c, ext=ext) self.add_msg(p) raise self.tls13_ADDED_SERVERHELLO()
def should_add_ServerHello(self): """ Selecting a cipher suite should be no trouble as we already caught the None case previously. Also, we do not manage extensions at all. """ if isinstance(self.mykey, PrivKeyRSA): kx = "RSA" elif isinstance(self.mykey, PrivKeyECDSA): kx = "ECDSA" usable_suites = get_usable_ciphersuites(self.cur_pkt.ciphers, kx) c = usable_suites[0] if self.preferred_ciphersuite in usable_suites: c = self.preferred_ciphersuite self.add_msg(TLSServerHello(cipher=c)) raise self.ADDED_SERVERHELLO()
def tls13_should_add_ServerHello(self): if isinstance(self.mykey, PrivKeyRSA): kx = "RSA" elif isinstance(self.mykey, PrivKeyECDSA): kx = "ECDSA" usable_suites = get_usable_ciphersuites(self.cur_pkt.ciphers, kx) c = usable_suites[0] group = next(iter(self.cur_session.tls13_client_pubshares)) ext = [TLS_Ext_SupportedVersion_SH(version="TLS 1.3")] ext += TLS_Ext_KeyShare_SH(server_share=KeyShareEntry(group=group)) if self.cur_session.sid is not None: p = TLS13ServerHello(cipher=c, sid=self.cur_session.sid, ext=ext) else: p = TLS13ServerHello(cipher=c, ext=ext) self.add_msg(p) raise self.tls13_ADDED_SERVERHELLO()
def tls13_should_add_HelloRetryRequest(self): self.add_record(is_tls13=False) if isinstance(self.mykey, PrivKeyRSA): kx = "RSA" elif isinstance(self.mykey, PrivKeyECDSA): kx = "ECDSA" usable_suites = get_usable_ciphersuites(self.cur_pkt.ciphers, kx) c = usable_suites[0] ext = [ TLS_Ext_SupportedVersion_SH(version="TLS 1.3"), TLS_Ext_KeyShare_HRR(selected_group=_tls_named_groups[self.curve]) ] # noqa: E501 if self.cookie: ext += TLS_Ext_Cookie() p = TLS13HelloRetryRequest(cipher=c, ext=ext) self.add_msg(p) self.flush_records() raise self.tls13_HANDLED_HELLORETRYREQUEST()
def post_build(self, pkt, pay): cs_val = None if self.cipher is None: common_cs = self.tls_session.sslv2_common_cs cs_vals = get_usable_ciphersuites(common_cs, "SSLv2") if len(cs_vals) == 0: warning("No known common cipher suite between SSLv2 Hellos.") cs_val = 0x0700c0 cipher = b"\x07\x00\xc0" else: cs_val = cs_vals[0] # XXX choose the best one cipher = struct.pack(">BH", cs_val >> 16, cs_val & 0x00ffff) cs_cls = _tls_cipher_suites_cls[cs_val] self.cipher = cs_val else: cipher = pkt[1:4] cs_val = struct.unpack("!I", b"\x00" + cipher)[0] if cs_val not in _tls_cipher_suites_cls: warning("Unknown ciphersuite %d from ClientMasterKey" % cs_val) cs_cls = None else: cs_cls = _tls_cipher_suites_cls[cs_val] if cs_cls: if (self.encryptedkey == b"" and len(self.tls_session.server_certs) > 0): # else, the user is responsible for export slicing & encryption key = randstring(cs_cls.cipher_alg.key_len) if self.clearkey == b"" and cs_cls.kx_alg.export: self.clearkey = key[:-5] if self.decryptedkey == b"": if cs_cls.kx_alg.export: self.decryptedkey = key[-5:] else: self.decryptedkey = key pubkey = self.tls_session.server_certs[0].pubKey self.encryptedkey = pubkey.encrypt(self.decryptedkey) if self.keyarg == b"" and cs_cls.cipher_alg.type == "block": self.keyarg = randstring(cs_cls.cipher_alg.block_size) clearkey = self.clearkey or b"" if self.clearkeylen is None: self.clearkeylen = len(clearkey) clearkeylen = struct.pack("!H", self.clearkeylen) encryptedkey = self.encryptedkey or b"" if self.encryptedkeylen is None: self.encryptedkeylen = len(encryptedkey) encryptedkeylen = struct.pack("!H", self.encryptedkeylen) keyarg = self.keyarg or b"" if self.keyarglen is None: self.keyarglen = len(keyarg) keyarglen = struct.pack("!H", self.keyarglen) s = (chb(pkt[0]) + cipher + clearkeylen + encryptedkeylen + keyarglen + clearkey + encryptedkey + keyarg) return s + pay
def post_build(self, pkt, pay): cs_val = None if self.cipher is None: common_cs = self.tls_session.sslv2_common_cs cs_vals = get_usable_ciphersuites(common_cs, "SSLv2") if len(cs_vals) == 0: warning("No known common cipher suite between SSLv2 Hellos.") cs_val = 0x0700c0 cipher = "\x07\x00\xc0" else: cs_val = cs_vals[0] #XXX choose the best one cipher = struct.pack(">BH", cs_val >> 16, cs_val & 0x00ffff) cs_cls = _tls_cipher_suites_cls[cs_val] self.cipher = cs_val else: cipher = pkt[1:4] cs_val = struct.unpack("!I", "\x00" + cipher)[0] if cs_val not in _tls_cipher_suites_cls: warning("Unknown ciphersuite %d from ClientMasterKey" % cs_val) cs_cls = None else: cs_cls = _tls_cipher_suites_cls[cs_val] if cs_cls: if (self.encryptedkey == "" and len(self.tls_session.server_certs) > 0): # else, the user is responsible for export slicing & encryption key = randstring(cs_cls.cipher_alg.key_len) if self.clearkey == "" and cs_cls.kx_alg.export: self.clearkey = key[:-5] if self.decryptedkey == "": if cs_cls.kx_alg.export: self.decryptedkey = key[-5:] else: self.decryptedkey = key pubkey = self.tls_session.server_certs[0].pubKey self.encryptedkey = pubkey.encrypt(self.decryptedkey) if self.keyarg == "" and cs_cls.cipher_alg.type == "block": self.keyarg = randstring(cs_cls.cipher_alg.block_size) clearkey = self.clearkey or "" if self.clearkeylen is None: self.clearkeylen = len(clearkey) clearkeylen = struct.pack("!H", self.clearkeylen) encryptedkey = self.encryptedkey or "" if self.encryptedkeylen is None: self.encryptedkeylen = len(encryptedkey) encryptedkeylen = struct.pack("!H", self.encryptedkeylen) keyarg = self.keyarg or "" if self.keyarglen is None: self.keyarglen = len(keyarg) keyarglen = struct.pack("!H", self.keyarglen) s = (pkt[0] + cipher + clearkeylen + encryptedkeylen + keyarglen + clearkey + encryptedkey + keyarg) return s + pay