Example #1
0
    def verify(self, key: JsonDict) -> bool:
        """Verifies 'signatures' over 'signed' that match the passed key by id.

        Arguments:
            key: A securesystemslib-style public key object.

        Raises:
            # TODO: Revise exception taxonomy
            tuf.exceptions.Error: None or multiple signatures found for key.
            securesystemslib.exceptions.FormatError: Key argument is malformed.
            securesystemslib.exceptions.CryptoError, \
                    securesystemslib.exceptions.UnsupportedAlgorithmError:
                Signing errors.

        Returns:
            A boolean indicating if the signature is valid for the passed key.

        """
        signatures_for_keyid = list(
            filter(lambda sig: sig['keyid'] == key['keyid'], self.signatures))

        if not signatures_for_keyid:
            raise tuf.exceptions.Error(f'no signature for key {key["keyid"]}.')

        if len(signatures_for_keyid) > 1:
            raise tuf.exceptions.Error(
                f'{len(signatures_for_keyid)} signatures for key '
                f'{key["keyid"]}, not sure which one to verify.')

        return verify_signature(key, signatures_for_keyid[0],
                                self.signed.to_canonical_bytes())
Example #2
0
    def test_sslib_sign(self):
        dicts = [self.rsakey_dict, self.ecdsakey_dict, self.ed25519key_dict]
        for scheme_dict in dicts:
            # Test generation of signatures.
            sslib_signer = SSlibSigner(scheme_dict)
            sig_obj = sslib_signer.sign(self.DATA)

            # Verify signature
            verified = KEYS.verify_signature(scheme_dict, sig_obj.to_dict(),
                    self.DATA)
            self.assertTrue(verified, "Incorrect signature.")

            # Removing private key from "scheme_dict".
            private = scheme_dict["keyval"]["private"]
            scheme_dict["keyval"]["private"] = ""
            sslib_signer.key_dict = scheme_dict

            with self.assertRaises((ValueError, FormatError)):
                sslib_signer.sign(self.DATA)

            scheme_dict["keyval"]["private"] = private

            # Test for invalid signature scheme.
            valid_scheme = scheme_dict["scheme"]
            scheme_dict["scheme"] = "invalid_scheme"
            sslib_signer = SSlibSigner(scheme_dict)

            with self.assertRaises((UnsupportedAlgorithmError, FormatError)):
                sslib_signer.sign(self.DATA)

            scheme_dict["scheme"] = valid_scheme
Example #3
0
    def verify(
        self,
        key: Mapping[str, Any],
        signed_serializer: Optional[SignedSerializer] = None,
    ) -> bool:
        """Verifies 'signatures' over 'signed' that match the passed key by id.

        Arguments:
            key: A securesystemslib-style public key object.
            signed_serializer: A SignedSerializer subclass instance that
                implements the desired canonicalization format. Per default a
                CanonicalJSONSerializer is used.

        Raises:
            # TODO: Revise exception taxonomy
            tuf.exceptions.Error: None or multiple signatures found for key.
            securesystemslib.exceptions.FormatError: Key argument is malformed.
            tuf.api.serialization.SerializationError:
                'signed' cannot be serialized.
            securesystemslib.exceptions.CryptoError, \
                    securesystemslib.exceptions.UnsupportedAlgorithmError:
                Signing errors.

        Returns:
            A boolean indicating if the signature is valid for the passed key.

        """
        signatures_for_keyid = list(
            filter(lambda sig: sig.keyid == key["keyid"], self.signatures)
        )

        if not signatures_for_keyid:
            raise exceptions.Error(f"no signature for key {key['keyid']}.")

        if len(signatures_for_keyid) > 1:
            raise exceptions.Error(
                f"{len(signatures_for_keyid)} signatures for key "
                f"{key['keyid']}, not sure which one to verify."
            )

        if signed_serializer is None:
            # Use local scope import to avoid circular import errors
            # pylint: disable=import-outside-toplevel
            from tuf.api.serialization.json import CanonicalJSONSerializer

            signed_serializer = CanonicalJSONSerializer()

        return verify_signature(
            key,
            signatures_for_keyid[0].to_dict(),
            signed_serializer.serialize(self.signed),
        )
Example #4
0
    def verify_signature(
        self,
        metadata: Metadata,
        signed_serializer: Optional[SignedSerializer] = None,
    ) -> None:
        """Verifies that the 'metadata.signatures' contains a signature made
        with this key, correctly signing 'metadata.signed'.

        Arguments:
            metadata: Metadata to verify
            signed_serializer: Optional; SignedSerializer to serialize
                'metadata.signed' with. Default is CanonicalJSONSerializer.

        Raises:
            UnsignedMetadataError: The signature could not be verified for a
                variety of possible reasons: see error message.
        """
        try:
            signature = metadata.signatures[self.keyid]
        except KeyError:
            raise exceptions.UnsignedMetadataError(
                f"no signature for key {self.keyid} found in metadata",
                metadata.signed,
            ) from None

        if signed_serializer is None:
            # pylint: disable=import-outside-toplevel
            from tuf.api.serialization.json import CanonicalJSONSerializer

            signed_serializer = CanonicalJSONSerializer()

        try:
            if not sslib_keys.verify_signature(
                    self.to_securesystemslib_key(),
                    signature.to_dict(),
                    signed_serializer.serialize(metadata.signed),
            ):
                raise exceptions.UnsignedMetadataError(
                    f"Failed to verify {self.keyid} signature",
                    metadata.signed,
                )
        except (
                sslib_exceptions.CryptoError,
                sslib_exceptions.FormatError,
                sslib_exceptions.UnsupportedAlgorithmError,
        ) as e:
            raise exceptions.UnsignedMetadataError(
                f"Failed to verify {self.keyid} signature",
                metadata.signed,
            ) from e
Example #5
0
def get_signature_status(signable,
                         role=None,
                         repository_name='default',
                         threshold=None,
                         keyids=None):
    """
  <Purpose>
    Return a dictionary representing the status of the signatures listed in
    'signable'. Signatures in the returned dictionary are identified by the
    signature keyid and can have a status of either:

    * bad -- Invalid signature
    * good -- Valid signature from key that is available in 'tuf.keydb', and is
      authorized for the passed role as per 'roledb' (authorization may be
      overwritten by passed 'keyids').
    * unknown -- Signature from key that is not available in 'tuf.keydb', or if
      'role' is None.
    * unknown signing schemes -- Signature from key with unknown signing
      scheme.
    * untrusted -- Valid signature from key that is available in 'tuf.keydb',
      but is not trusted for the passed role as per 'roledb' or the passed
      'keyids'.

    NOTE: The result may contain duplicate keyids or keyids that reference the
    same key, if 'signable' lists multiple signatures from the same key.

  <Arguments>
    signable:
      A dictionary containing a list of signatures and a 'signed' identifier.
      signable = {'signed': 'signer',
                  'signatures': [{'keyid': keyid,
                                  'sig': sig}]}

      Conformant to tuf.formats.SIGNABLE_SCHEMA.

    role:
      TUF role string (e.g. 'root', 'targets', 'snapshot' or timestamp).

    threshold:
      Rather than reference the role's threshold as set in roledb, use
      the given 'threshold' to calculate the signature status of 'signable'.
      'threshold' is an integer value that sets the role's threshold value, or
      the minimum number of signatures needed for metadata to be considered
      fully signed.

    keyids:
      Similar to the 'threshold' argument, use the supplied list of 'keyids'
      to calculate the signature status, instead of referencing the keyids
      in roledb for 'role'.

  <Exceptions>
    securesystemslib.exceptions.FormatError, if 'signable' does not have the
    correct format.

    tuf.exceptions.UnknownRoleError, if 'role' is not recognized.

  <Side Effects>
    None.

  <Returns>
    A dictionary representing the status of the signatures in 'signable'.
    Conformant to tuf.formats.SIGNATURESTATUS_SCHEMA.
  """

    # Do the arguments have the correct format?  This check will ensure that
    # arguments have the appropriate number of objects and object types, and that
    # all dict keys are properly named.  Raise
    # 'securesystemslib.exceptions.FormatError' if the check fails.
    formats.SIGNABLE_SCHEMA.check_match(signable)
    sslib_formats.NAME_SCHEMA.check_match(repository_name)

    if role is not None:
        formats.ROLENAME_SCHEMA.check_match(role)

    if threshold is not None:
        formats.THRESHOLD_SCHEMA.check_match(threshold)

    if keyids is not None:
        sslib_formats.KEYIDS_SCHEMA.check_match(keyids)

    # The signature status dictionary returned.
    signature_status = {}
    good_sigs = []
    bad_sigs = []
    unknown_sigs = []
    untrusted_sigs = []
    unknown_signing_schemes = []

    # Extract the relevant fields from 'signable' that will allow us to identify
    # the different classes of keys (i.e., good_sigs, bad_sigs, etc.).
    signed = sslib_formats.encode_canonical(signable['signed']).encode('utf-8')
    signatures = signable['signatures']

    # Iterate the signatures and enumerate the signature_status fields.
    # (i.e., good_sigs, bad_sigs, etc.).
    for signature in signatures:
        keyid = signature['keyid']

        # Does the signature use an unrecognized key?
        try:
            key = keydb.get_key(keyid, repository_name)

        except exceptions.UnknownKeyError:
            unknown_sigs.append(keyid)
            continue

        # Does the signature use an unknown/unsupported signing scheme?
        try:
            valid_sig = sslib_keys.verify_signature(key, signature, signed)

        except sslib_exceptions.UnsupportedAlgorithmError:
            unknown_signing_schemes.append(keyid)
            continue

        # We are now dealing with either a trusted or untrusted key...
        if valid_sig:
            if role is not None:

                # Is this an unauthorized key? (a keyid associated with 'role')
                # Note that if the role is not known, tuf.exceptions.UnknownRoleError
                # is raised here.
                if keyids is None:
                    keyids = roledb.get_role_keyids(role, repository_name)

                if keyid not in keyids:
                    untrusted_sigs.append(keyid)
                    continue

            # This is an unset role, thus an unknown signature.
            else:
                unknown_sigs.append(keyid)
                continue

            # Identify good/authorized key.
            good_sigs.append(keyid)

        else:
            # This is a bad signature for a trusted key.
            bad_sigs.append(keyid)

    # Retrieve the threshold value for 'role'.  Raise
    # tuf.exceptions.UnknownRoleError if we were given an invalid role.
    if role is not None:
        if threshold is None:
            # Note that if the role is not known, tuf.exceptions.UnknownRoleError is
            # raised here.
            threshold = roledb.get_role_threshold(
                role, repository_name=repository_name)

        else:
            logger.debug('Not using roledb.py\'s threshold for ' + repr(role))

    else:
        threshold = 0

    # Build the signature_status dict.
    signature_status['threshold'] = threshold
    signature_status['good_sigs'] = good_sigs
    signature_status['bad_sigs'] = bad_sigs
    signature_status['unknown_sigs'] = unknown_sigs
    signature_status['untrusted_sigs'] = untrusted_sigs
    signature_status['unknown_signing_schemes'] = unknown_signing_schemes

    return signature_status
Example #6
0
def verify_data(signature, data):
    return verify_signature(get_private_key(), signature, data)