예제 #1
0
    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")
예제 #2
0
        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)