def __init__(self, metadata_type, reserved_flags, public_key, **kwargs): super().__init__() self.metadata_type = metadata_type self.reserved_flags = reserved_flags self.public_key = bytes(public_key) self.signature = bytes( kwargs["signature"] ) if "signature" in kwargs and kwargs["signature"] else None # Special case: free-for-all entries are allowed to go with zero key and without sig check if "unsigned" in kwargs and kwargs["unsigned"]: self.public_key = NULL_KEY self.signature = NULL_SIG return if "skip_key_check" in kwargs and kwargs["skip_key_check"]: return # This is integrity check for FFA payloads. if self.public_key == NULL_KEY: if self.signature == NULL_SIG: return raise InvalidSignatureException( "Tried to create FFA payload with non-null signature") serialized_data = default_serializer.pack_serializable(self) if "key" in kwargs and kwargs["key"]: key = kwargs["key"] if self.public_key != key.pub().key_to_bin()[10:]: raise KeysMismatchException(self.public_key, key.pub().key_to_bin()[10:]) self.signature = default_eccrypto.create_signature( key, serialized_data) elif "signature" in kwargs: # This check ensures that an entry with a wrong signature will not proliferate further if not default_eccrypto.is_valid_signature( default_eccrypto.key_from_public_bin(b"LibNaCLPK:" + self.public_key), serialized_data, self.signature): raise InvalidSignatureException( "Tried to create payload with wrong signature") else: raise InvalidSignatureException( "Tried to create payload without signature")
def __init__(self, *args, **kwargs): """ Initialize a metadata object. All this dance is required to ensure that the signature is there and it is correct. """ skip_key_check = False # FIXME: refactor this method by moving different ways to create an entry into separate methods # Process special keyworded arguments # "sign_with" argument given, sign with it private_key_override = None if "sign_with" in kwargs: kwargs["public_key"] = database_blob( kwargs["sign_with"].pub().key_to_bin()[10:]) private_key_override = kwargs.pop("sign_with") # Free-for-all entries require special treatment if "public_key" in kwargs and kwargs["public_key"] == b"": # We have to give the entry an unique sig to honor the DB constraints. We use the entry's id_ # as the sig to keep it unique and short. The uniqueness is guaranteed by DB as it already # imposes uniqueness constraints on the id_+public_key combination. if "id_" in kwargs: kwargs["signature"] = None skip_key_check = True else: # Trying to create an FFA entry without specifying the id_ should be considered an error, # because assigning id_ automatically by clock breaks anonymity. # FFA entries should be "timeless" and anonymous. raise InvalidChannelNodeException( "Attempted to create %s free-for-all (unsigned) object without specifying id_ : " % str(self.__class__.__name__)) # For putting legacy/test stuff in skip_key_check = kwargs.pop("skip_key_check", skip_key_check) if "timestamp" not in kwargs: kwargs["timestamp"] = clock.tick() if "id_" not in kwargs: kwargs["id_"] = int(random.getrandbits(63)) if not private_key_override and not skip_key_check: # No key/signature given, sign with our own key. if ("signature" not in kwargs) and ( ("public_key" not in kwargs) or (kwargs["public_key"] == database_blob( self._my_key.pub().key_to_bin()[10:]))): private_key_override = self._my_key # Key/signature given, check them for correctness elif ("public_key" in kwargs) and ("signature" in kwargs): try: self._payload_class(**kwargs) except InvalidSignatureException: raise InvalidSignatureException( f"Attempted to create {str(self.__class__.__name__)} object with invalid signature/PK: " + (hexlify(kwargs["signature"]) if "signature" in kwargs else "empty signature ") + " / " + (hexlify(kwargs["public_key"]) if "public_key" in kwargs else " empty PK")) if private_key_override: # Get default values for Pony class attributes. We have to do it manually because we need # to know the payload signature *before* creating the object. kwargs = generate_dict_from_pony_args( self.__class__, skip_list=["signature", "public_key"], **kwargs) payload = self._payload_class(**dict( kwargs, public_key=private_key_override.pub().key_to_bin()[10:], key=private_key_override, metadata_type=self.metadata_type, )) kwargs["public_key"] = payload.public_key kwargs["signature"] = payload.signature super().__init__(*args, **kwargs)