From 8a61d2c8d5650aea1c89e0a8b3757c4d89985c39 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Tue, 4 Oct 2022 06:59:33 +0200 Subject: [PATCH] Fixed missing validation in announce processing --- RNS/Destination.py | 57 +++++++++++++++++++++++++++++----------------- RNS/Identity.py | 32 ++++++++++++++++---------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/RNS/Destination.py b/RNS/Destination.py index 56fd607..49ddc32 100755 --- a/RNS/Destination.py +++ b/RNS/Destination.py @@ -70,7 +70,7 @@ class Destination: directions = [IN, OUT] @staticmethod - def full_name(app_name, *aspects): + def expand_name(identity, app_name, *aspects): """ :returns: A string containing the full human-readable name of the destination, for an app_name and a number of aspects. """ @@ -81,20 +81,27 @@ class Destination: name = app_name for aspect in aspects: if "." in aspect: raise ValueError("Dots can't be used in aspects") - name = name + "." + aspect + name += "." + aspect + + if identity != None: + name += "." + identity.hexhash return name - @staticmethod - def hash(app_name, *aspects): - """ - :returns: A destination name in adressable hash form, for an app_name and a number of aspects. - """ - name = Destination.full_name(app_name, *aspects) + # @staticmethod + # def hash(identity, app_name, *aspects): + # """ + # :returns: A destination name in adressable hash form, for an app_name and a number of aspects. + # """ + # base_name = Destination.expand_name(None, app_name, *aspects) + # hash_material = RNS.Identity.full_hash(base_name.encode("utf-8")) - # Create a digest for the destination - return RNS.Identity.full_hash(name.encode("utf-8"))[:RNS.Reticulum.TRUNCATED_HASHLENGTH//8] + # if identity != None: + # hash_material += identity.hash + + # # Create a digest for the destination + # return RNS.Identity.full_hash(hash_material)[:RNS.Reticulum.TRUNCATED_HASHLENGTH//8] @staticmethod def app_and_aspects_from_name(full_name): @@ -129,9 +136,6 @@ class Destination: self.links = [] - if identity != None and type == Destination.SINGLE: - aspects = aspects+(identity.hexhash,) - if identity == None and direction == Destination.IN and self.type != Destination.PLAIN: identity = RNS.Identity() aspects = aspects+(identity.hexhash,) @@ -140,12 +144,18 @@ class Destination: raise TypeError("Selected destination type PLAIN cannot hold an identity") self.identity = identity + self.full_name = Destination.expand_name(identity, app_name, *aspects) - self.name = Destination.full_name(app_name, *aspects) - self.hash = Destination.hash(app_name, *aspects) + self.name_hash = RNS.Identity.full_hash(self.expand_name(None, app_name, *aspects).encode("utf-8")) + self.addr_hash_material = self.name_hash + if self.identity != None: + self.addr_hash_material += self.identity.hash + + # Generate the destination address hash + self.hash = RNS.Identity.full_hash(self.addr_hash_material)[:RNS.Reticulum.TRUNCATED_HASHLENGTH//8] self.hexhash = self.hash.hex() - self.default_app_data = None + self.default_app_data = None self.callback = None self.proofcallback = None @@ -156,10 +166,10 @@ class Destination: """ :returns: A human-readable representation of the destination including addressable hash and full name. """ - return "<"+self.name+"/"+self.hexhash+">" + return "<"+self.full_name+"/"+self.hexhash+">" - def announce(self, app_data=None, path_response=False): + def announce(self, app_data=None, path_response=False, send=True): """ Creates an announce packet for this destination and broadcasts it on all relevant interfaces. Application specific data can be added to the announce. @@ -181,13 +191,13 @@ class Destination: if isinstance(returned_app_data, bytes): app_data = returned_app_data - signed_data = self.hash+self.identity.get_public_key()+random_hash + signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash if app_data != None: signed_data += app_data signature = self.identity.sign(signed_data) - announce_data = self.identity.get_public_key()+random_hash+signature + announce_data = self.identity.get_public_key()+self.name_hash+random_hash+signature if app_data != None: announce_data += app_data @@ -197,7 +207,12 @@ class Destination: else: announce_context = RNS.Packet.NONE - RNS.Packet(self, announce_data, RNS.Packet.ANNOUNCE, context = announce_context).send() + announce_packet = RNS.Packet(self, announce_data, RNS.Packet.ANNOUNCE, context = announce_context) + + if send: + announce_packet.send() + else: + return announce_packet def accepts_links(self, accepts = None): """ diff --git a/RNS/Identity.py b/RNS/Identity.py index 3d2ecd8..24bc901 100644 --- a/RNS/Identity.py +++ b/RNS/Identity.py @@ -214,30 +214,38 @@ class Identity: if packet.packet_type == RNS.Packet.ANNOUNCE: destination_hash = packet.destination_hash public_key = packet.data[:Identity.KEYSIZE//8] - random_hash = packet.data[Identity.KEYSIZE//8:Identity.KEYSIZE//8+10] - signature = packet.data[Identity.KEYSIZE//8+10:Identity.KEYSIZE//8+10+Identity.KEYSIZE//8] + name_hash = packet.data[Identity.KEYSIZE//8:Identity.KEYSIZE//8+Identity.HASHLENGTH//8] + random_hash = packet.data[Identity.KEYSIZE//8+Identity.HASHLENGTH//8:Identity.KEYSIZE//8+Identity.HASHLENGTH//8+10] + signature = packet.data[Identity.KEYSIZE//8+Identity.HASHLENGTH//8+10:Identity.KEYSIZE//8+Identity.HASHLENGTH//8+10+Identity.SIGLENGTH//8] app_data = b"" - if len(packet.data) > Identity.KEYSIZE//8+10+Identity.KEYSIZE//8: + if len(packet.data) > Identity.KEYSIZE//8+Identity.HASHLENGTH//8+10+Identity.SIGLENGTH//8: app_data = packet.data[Identity.KEYSIZE//8+10+Identity.KEYSIZE//8:] - signed_data = destination_hash+public_key+random_hash+app_data + signed_data = destination_hash+public_key+name_hash+random_hash+app_data - if not len(packet.data) > Identity.KEYSIZE//8+10+Identity.KEYSIZE//8: + if not len(packet.data) > Identity.KEYSIZE//8+Identity.HASHLENGTH//8+10+Identity.SIGLENGTH//8: app_data = None announced_identity = Identity(create_keys=False) announced_identity.load_public_key(public_key) if announced_identity.pub != None and announced_identity.validate(signature, signed_data): - RNS.Identity.remember(packet.get_hash(), destination_hash, public_key, app_data) - del announced_identity + hash_material = name_hash+announced_identity.hash + expected_hash = RNS.Identity.full_hash(hash_material)[:RNS.Reticulum.TRUNCATED_HASHLENGTH//8] + + if destination_hash == expected_hash: + RNS.Identity.remember(packet.get_hash(), destination_hash, public_key, app_data) + del announced_identity + + if hasattr(packet, "transport_id") and packet.transport_id != None: + RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received via "+RNS.prettyhexrep(packet.transport_id)+" on "+str(packet.receiving_interface), RNS.LOG_EXTREME) + else: + RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface), RNS.LOG_EXTREME) + + return True - if hasattr(packet, "transport_id") and packet.transport_id != None: - RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received via "+RNS.prettyhexrep(packet.transport_id)+" on "+str(packet.receiving_interface), RNS.LOG_EXTREME) else: - RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface), RNS.LOG_EXTREME) - - return True + return False else: RNS.log("Received invalid announce for "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG)