async def login(self, client, username): assert username == "username" pid = 1001 stick = kerberos.ServerTicket() stick.timestamp = common.DateTime.now() stick.source = pid stick.session_key = bytes(32) ctick = kerberos.ClientTicket() ctick.session_key = bytes(32) ctick.target = 100 ctick.internal = stick.encrypt(b"testkey", self.settings) kerb = kerberos.KeyDerivationOld(65000, 1024) key = kerb.derive_key(b"password", pid) connection_data = authentication.RVConnectionData() connection_data.main_station = common.StationURL(address=HOST, port=12346, PID=100, sid=1) connection_data.special_protocols = [] connection_data.special_station = common.StationURL() connection_data.server_time = common.DateTime.now() response = rmc.RMCResponse() response.result = common.Result.success() response.pid = pid response.ticket = ctick.encrypt(key, self.settings) response.connection_data = connection_data response.server_name = "server build name" return response
def handle_connection_request(self, packet): logger.debug("Received connection request: %i bytes", len(packet.payload)) if not self.server_key: logger.debug("No validation needed, accepting connection") return b"" if not packet.payload: logger.error("Received empty connection request for secure server") self.cleanup() return stream = streams.StreamIn(packet.payload, self.settings) ticket = stream.buffer() request = stream.buffer() server_ticket = kerberos.ServerTicket() try: server_ticket.decrypt(ticket, self.server_key, self.settings) except ValueError: logger.error("Server ticket decryption failed") self.cleanup() return if server_ticket.expiration.timestamp() < time.time(): logger.error("Ticket has expired") self.cleanup() return kerb = kerberos.KerberosEncryption(server_ticket.session_key) try: decrypted = kerb.decrypt(request) except ValueError: logger.error("Ticket decryption failed") self.cleanup() return if len(decrypted) != self.settings.get("common.pid_size") + 8: logger.error("Invalid ticket size") self.cleanup() return stream = streams.StreamIn(decrypted, self.settings) if stream.pid() != server_ticket.source_pid: logger.error("Invalid pid in kerberos ticket") self.cleanup() return self.pid = server_ticket.source_pid stream.u32() #Don't care about cid check_value = stream.u32() logger.debug("Connection request was validated successfully") self.set_session_key(server_ticket.session_key) return struct.pack("<II", 4, (check_value + 1) & 0xFFFFFFFF)
def generate_ticket(self, user_pid, server_pid, user_key, server_key): session_key = secrets.token_bytes(32) internal = kerberos.ServerTicket() internal.timestamp = common.DateTime.now() internal.source = user_pid internal.session_key = session_key ticket = kerberos.ClientTicket() ticket.session_key = session_key ticket.target = server_pid ticket.internal = internal.encrypt(server_key, self.settings) return ticket.encrypt(user_key, self.settings)
def test_server_ticket(): ticket = kerberos.ServerTicket() ticket.timestamp = common.DateTime.fromtimestamp(1596279690) ticket.session_key = bytes(range(32)) ticket.source = 123456 s = settings.default() data = ticket.encrypt(b"key", s) ticket = kerberos.ServerTicket.decrypt(data, b"key", s) assert ticket.timestamp.timestamp() == 1596279690 assert ticket.session_key == bytes(range(32)) assert ticket.source == 123456
def generate_ticket(self, source, target): settings = self.settings user_key = derive_key(source) server_key = derive_key(target) session_key = secrets.token_bytes(settings.get("kerberos.key_size")) internal = kerberos.ServerTicket() internal.expiration = common.DateTime.fromtimestamp(time.time() + 120) internal.source_pid = source.pid internal.session_key = session_key ticket = kerberos.ClientTicket() ticket.session_key = session_key ticket.target_pid = target.pid ticket.internal = internal.encrypt(server_key, settings) return ticket.encrypt(user_key, settings)
def generate_ticket(self, source, target): settings = self.settings user_key = derive_key(source) server_key = derive_key(target) session_key = secrets.token_bytes(settings["kerberos.key_size"]) internal = kerberos.ServerTicket() internal.timestamp = common.DateTime.now() internal.source = source.pid internal.session_key = session_key ticket = kerberos.ClientTicket() ticket.session_key = session_key ticket.target = target.pid ticket.internal = internal.encrypt(server_key, settings) return ticket.encrypt(user_key, settings)
def validate_connection_request(self, payload): if not self.server_key or not payload: return True stream = streams.StreamIn(payload, self.settings) ticket = stream.buffer() request = stream.buffer() self.server_ticket = kerberos.ServerTicket() try: self.server_ticket.decrypt(ticket, self.server_key, self.settings) except ValueError: logger.error("Server ticket decryption failed") return False if self.server_ticket.expiration.timestamp() < time.time(): logger.error("Ticket has expired") return False kerb = kerberos.KerberosEncryption(self.server_ticket.session_key) try: decrypted = kerb.decrypt(request) except ValueError: logger.error("Ticket decryption failed") return False self.set_session_key(self.server_ticket.session_key) if len(decrypted) != self.settings.get("common.pid_size") + 8: logger.error("Invalid ticket size") return False stream = streams.StreamIn(decrypted, self.settings) if stream.pid() != self.server_ticket.source_pid: logger.error("Invalid pid in kerberos ticket") return False stream.u32() #Don't care about cid self.check_value = stream.u32() return True
async def test_credentials(): s = settings.default() async def handler(client): assert client.pid() == 1000 ticket = kerberos.ServerTicket() ticket.timestamp = common.DateTime.now() ticket.source = 1000 ticket.session_key = bytes(32) data = ticket.encrypt(b"server key", s) ticket = kerberos.ClientTicket() ticket.session_key = bytes(32) ticket.target = 1001 ticket.internal = data creds = kerberos.Credentials(ticket, 1000, 2000) async with prudp.serve(handler, s, HOST, 12345, key=b"server key"): async with prudp.connect(s, HOST, 12345, credentials=creds) as client: assert client.pid() == 1000