def client(auth, target_addr): parser = yield from iofree.get_parser() parser.respond(data=socks5.Handshake( ..., [socks5.AuthMethod.no_auth, socks5.AuthMethod.user_auth]).binary) server_selection = yield from socks5.ServerSelection.get_value() if server_selection.method not in ( socks5.AuthMethod.no_auth, socks5.AuthMethod.user_auth, ): parser.respond(close=True, exc=ProtocolError("no method to choose")) if auth and (server_selection.method is socks5.AuthMethod.user_auth): parser.respond(data=socks5.UsernameAuth(..., auth[0].decode(), auth[1].decode()).binary) yield from socks5.UsernameAuthReply.get_value() parser.respond( data=socks5.ClientRequest(..., socks5.Cmd.connect, ..., socks5.Addr.from_tuple(target_addr)).binary) reply = yield from socks5.Reply.get_value() if reply.rep is not socks5.Rep.succeeded: parser.respond(close=True, exc=ProtocolError(f"bad reply: {reply}")) parser.respond(result=reply)
def socks5_request(auth=False): parser = yield from iofree.get_parser() ver, nmethods = yield from iofree.read_struct("!BB") assert ver == 5, f"bad socks version: {ver}" assert nmethods != 0, f"nmethods can't be 0" methods = yield from iofree.read(nmethods) if auth and b"\x02" not in methods: parser.write(b"\x05\x02") raise Exception("server needs authentication") elif b"\x00" not in methods: parser.write(b"\x05\x00") raise Exception("method not support") if auth: parser.write(b"\x05\x02") auth_ver, username_length = yield from iofree.read_struct("!BB") assert auth_ver == 1, f"invalid auth version {auth_ver}" username = yield from iofree.read(username_length) password_length = (yield from iofree.read(1))[0] password = yield from iofree.read(password_length) if (username, password) != auth: parser.write(b"\x01\x01") raise Exception("authenticate failed") else: parser.write(b"\x01\x00") else: parser.write(b"\x05\x00") ver, cmd, rsv = yield from iofree.read_struct("!BBB") if cmd == 1: # connect pass elif cmd == 2: # bind raise Exception("doesn't support bind yet") elif cmd == 3: # associate raise Exception("doesn't support associate yes") else: raise Exception(f"unknown cmd: {cmd}") target_addr = yield from read_addr() return target_addr, cmd
def simple(): parser = yield from iofree.get_parser() yield from iofree.read(1) assert parser.has_more_data() assert not parser.finished() raise Exception("special")
def second(): parser = yield from iofree.get_parser() for i in range(10): a = yield from schema.Group(x=schema.uint16be, y=schema.uint8) parser.respond(result=a)
def first(): parser = yield from iofree.get_parser() for i in range(10): a = yield from schema.Group(x=schema.uint8, y=schema.uint16be) parser.respond(result=a.binary[1:] + a.binary[:1]) return b""
def _client(self): parser = yield from iofree.get_parser() parser.respond(data=self.client_hello()) plain_text = yield from models.TLSPlaintext.get_value() assert plain_text.content_type is models.ContentType.handshake self.peer_handshake = models.Handshake.parse(plain_text.fragment) self.handshake_context.extend(plain_text.fragment) print("plaintext handshake:", self.peer_handshake.msg_type) server_hello = self.peer_handshake.msg peer_pk = server_hello.extensions_dict[ models.ExtensionType.key_share].key_exchange shared_key = crypto_scalarmult(bytes(self.private_key), peer_pk) self.TLSCipher = server_hello.get_cipher() key_index = server_hello.extensions_dict.get( models.ExtensionType.pre_shared_key) psk = None if key_index is None else self.psk_list[key_index] self.key_scheduler = self.TLSCipher.tls_hash.scheduler(shared_key, psk) secret = self.key_scheduler.server_handshake_traffic_secret( self.handshake_context) # server handshake cipher self.peer_cipher = self.TLSCipher(secret) self.client_handshake_traffic_secret = self.key_scheduler.client_handshake_traffic_secret( self.handshake_context) plain_text = yield from models.TLSPlaintext.get_value() assert plain_text.content_type is models.ContentType.change_cipher_spec print("plaintext:", plain_text.content_type) server_finished = False while not server_finished: plain_text = yield from models.TLSPlaintext.get_value() assert plain_text.content_type is models.ContentType.application_data content = self.peer_cipher.decrypt(plain_text.fragment, plain_text.binary[:5]) inner_text = models.TLSInnerPlaintext.parse(content) assert inner_text.content_type is models.ContentType.handshake handshake = models.Handshake.parse(inner_text.content) print("inner_text:", handshake.msg_type) if handshake.msg_type is models.HandshakeType.finished: assert handshake.msg == self.peer_cipher.verify_data( self.handshake_context ), "server handshake finished does not match" server_finished = True self.handshake_context.extend(inner_text.content) # server application cipher self.server_secret = self.key_scheduler.server_application_traffic_secret_0( self.handshake_context) self.peer_cipher = self.TLSCipher(self.server_secret) parser.respond(data=self.client_finish(), result=True) print("connected") while True: plain_text = yield from models.TLSPlaintext.get_value() if plain_text.is_overflow(): parser.respond( data=self.pack_fatal( models.AlertDescription.record_overflow), close=True, exc=ProtocolError("text overflow"), ) return if plain_text.content_type is models.ContentType.application_data: content = self.peer_cipher.decrypt( plain_text.fragment, plain_text.binary[:5]) # .rstrip(b"\x00") inner_text = models.TLSInnerPlaintext.parse(content) if inner_text.content_type is models.ContentType.handshake: handshake = models.Handshake.parse(inner_text.content) print("inner_text:", handshake.msg_type) if handshake.msg_type is models.HandshakeType.key_update: self.server_secret = self.key_scheduler.application_traffic_secret_N( self.server_secret) self.peer_cipher = self.TLSCipher(self.server_secret) self.handshake_context.extend(inner_text.content) elif inner_text.content_type is models.ContentType.application_data: parser.respond(result=inner_text.content) else: print(inner_text) elif plain_text.content_type is models.ContentType.alert: print(models.Alert.parse(plain_text.fragment)) else: print(plain_text.content_type)
def tls_response(self): parser = yield from iofree.get_parser() while True: head = yield from iofree.read(5) assert head[ 1:3] == b"\x03\x03", f"bad legacy_record_version {head[1:3]}" length = int.from_bytes(head[3:], "big") if (head[0] == ContentType.application_data and length > (16384 + 256)) or (head[0] != ContentType.application_data and length > 16384): parser.write(self.pack_fatal(AlertDescription.record_overflow)) raise Alert(AlertLevel.fatal, AlertDescription.record_overflow) content = memoryview((yield from iofree.read(length))) if head[0] == ContentType.alert: level = AlertLevel.from_value(content[0]) description = AlertDescription.from_value(content[1]) raise Alert(level, description) elif head[0] == ContentType.handshake: self.peer_handshake = self.unpack_handshake(content) assert (self.peer_handshake.handshake_type == HandshakeType.server_hello), "expect server hello" peer_pk = self.peer_handshake.extensions[ ExtensionType.key_share].key_exchange shared_key = crypto_scalarmult(bytes(self.private_key), peer_pk) TLSCipher = self.peer_handshake.cipher_suite self.TLSCipher = TLSCipher key_index = self.peer_handshake.extensions.get( ExtensionType.pre_shared_key) psk = None if key_index is None else self.psk_list[key_index] key_scheduler = TLSCipher.tls_hash.scheduler(shared_key, psk) self.key_scheduler = key_scheduler secret = key_scheduler.server_handshake_traffic_secret( self.handshake_context) # server handshake cipher self.peer_cipher = TLSCipher(secret) client_handshake_traffic_secret = key_scheduler.client_handshake_traffic_secret( self.handshake_context) elif head[0] == ContentType.application_data: plaintext = self.peer_cipher.decrypt(content, head).rstrip(b"\x00") content_type = ContentType.from_value(plaintext[-1]) if content_type == ContentType.handshake: self.unpack_handshake(plaintext[:-1]) if self.server_finished: if self.early_data: eoe_data = HandshakeType.end_of_early_data.pack_data( b"") # self.handshake_context.extend(eoe_data) inner_plaintext = ContentType.handshake.tls_inner_plaintext( eoe_data) record = self.cipher.tls_ciphertext( inner_plaintext) parser.write(record) # client handshake cipher cipher = TLSCipher(client_handshake_traffic_secret) client_finished = cipher.verify_data( self.handshake_context) client_finished_data = HandshakeType.finished.pack_data( client_finished) inner_plaintext = ContentType.handshake.tls_inner_plaintext( client_finished_data) record = cipher.tls_ciphertext(inner_plaintext) change_cipher_spec = ContentType.change_cipher_spec.tls_plaintext( b"\x01") parser.write(change_cipher_spec + record) # server application cipher server_secret = key_scheduler.server_application_traffic_secret_0( self.handshake_context) self.peer_cipher = TLSCipher(server_secret) self.server_finished = False # client application cipher client_secret = key_scheduler.client_application_traffic_secret_0( self.handshake_context) self.cipher = TLSCipher(client_secret) self.handshake_context.extend(client_finished_data) elif content_type == ContentType.application_data: self.data_callback(plaintext[:-1]) elif content_type == ContentType.alert: level = AlertLevel.from_value(plaintext[0]) description = AlertDescription.from_value(plaintext[1]) raise Alert(level, description) elif content_type == ContentType.invalid: raise Exception("invalid content type") else: raise Exception(f"unexpected content type {content_type}") elif head[0] == ContentType.change_cipher_spec: assert content == b"\x01", "change_cipher should be 0x01" else: raise Exception(f"Unknown content type: {head[0]}")