Skip to content

Commit

Permalink
Raise on bad signature count in Metadata.verify
Browse files Browse the repository at this point in the history
Change Metadata.verify(key) behavior to raise an exception if
none or multiple signatures for the passed key are found on the
Metadata object.

Signed-off-by: Lukas Puehringer <[email protected]>
  • Loading branch information
lukpueh committed Sep 8, 2020
1 parent 520bc20 commit 88e64a1
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 25 deletions.
27 changes: 15 additions & 12 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def setUpModule():

# Since setUpModule is called after imports we need to import conditionally.
if IS_PY_VERSION_SUPPORTED:
import tuf.exceptions
from tuf.api.metadata import (
Metadata,
Snapshot,
Expand Down Expand Up @@ -152,12 +153,9 @@ def test_sign_verify(self):

# ... it has a single existing signature,
self.assertTrue(len(metadata_obj.signatures) == 1)
# ... valid for the correct key, but
# ... which is valid for the correct key.
self.assertTrue(metadata_obj.verify(
self.keystore['targets']['public']))
# ... invalid for an unrelated key.
self.assertFalse(metadata_obj.verify(
self.keystore['snapshot']['public']))

# Append a new signature with the unrelated key and assert that ...
metadata_obj.sign(self.keystore['snapshot']['private'], append=True)
Expand All @@ -177,15 +175,20 @@ def test_sign_verify(self):
self.assertTrue(metadata_obj.verify(
self.keystore['timestamp']['public']))


# Update the metadata, invalidating the existing signature, append
# a new signature with the same key, and assert that ...
metadata_obj.signed.bump_version()
# Assert exception if there are more than one signatures for a key
metadata_obj.sign(self.keystore['timestamp']['private'], append=True)
# ... verify returns False, because all signatures identified by a
# keyid must be valid
self.assertFalse(metadata_obj.verify(
self.keystore['timestamp']['public']))
with self.assertRaises(tuf.exceptions.Error) as ctx:
metadata_obj.verify(self.keystore['timestamp']['public'])
self.assertTrue(
'2 signatures for key' in str(ctx.exception),
str(ctx.exception))

# Assert exception if there is no signature for a key
with self.assertRaises(tuf.exceptions.Error) as ctx:
metadata_obj.verify(self.keystore['targets']['public'])
self.assertTrue(
'no signature for' in str(ctx.exception),
str(ctx.exception))


def test_metadata_base(self):
Expand Down
27 changes: 14 additions & 13 deletions tuf/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

import iso8601
import tuf.formats
import tuf.exceptions


# Types
Expand Down Expand Up @@ -242,33 +243,33 @@ def verify(self, key: JsonDict) -> bool:
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 all identified signatures are valid. False
if no signature was found for the keyid or any of the found
signatures is invalid.
FIXME: Is this behavior expected? An alternative approach would be
to raise an exception if no signature is found for the keyid,
and/or if more than one sigantures are found for the keyid.
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:
return False
raise tuf.exceptions.Error(
f'no signature for key {key["keyid"]}.')

for signature in signatures_for_keyid:
if not verify_signature(
key, signature, self.signed.to_canonical_bytes()):
return False
elif 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.')
else:
return verify_signature(
key, signatures_for_keyid[0],
self.signed.to_canonical_bytes())

return True


class Signed:
Expand Down

0 comments on commit 88e64a1

Please sign in to comment.