Skip to content

Commit

Permalink
Metadata API: verify_delegate: refactor
Browse files Browse the repository at this point in the history
* Rename arguments so connection between the role name and the
  metadata is stronger.
* Also add a comment on the list comprehension + next() trick.
* Add return value annotation
* Raise early if delegations is None to make the flow more obvious
  (and modify test case so we have coverage for the new case)

Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
  • Loading branch information
Jussi Kukkonen committed Jul 8, 2021
1 parent 48b58d9 commit 271d5b7
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 25 deletions.
6 changes: 1 addition & 5 deletions tests/repository_data/repository/metadata/role2.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@
"signatures": [
{
"keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a",
"sig": "6c32f8cc2c642803a7b3b022ede0cf727e82964c1aa934571ef366bd5050ed02cfe3fdfe5477c08d0cbcc2dd17bb786d37ab1ce2b27e01ad79faf087594e0300"
"sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403"
}
],
"signed": {
"_type": "targets",
"delegations": {
"keys": {},
"roles": []
},
"expires": "2030-01-01T00:00:00Z",
"spec_version": "1.0.0",
"targets": {},
Expand Down
3 changes: 3 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,9 @@ def test_metadata_verify_delegate(self):
root.verify_delegate('role1', role1)
with self.assertRaises(ValueError):
targets.verify_delegate('targets', targets)
# verify fails when delegator has no delegations
with self.assertRaises(ValueError):
role2.verify_delegate('role1', role1)

# verify fails when delegate content is modified
expires = snapshot.signed.expires
Expand Down
43 changes: 23 additions & 20 deletions tuf/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,16 +271,16 @@ def sign(

def verify_delegate(
self,
role_name: str,
delegate: "Metadata",
delegated_role: str,
delegated_metadata: "Metadata",
signed_serializer: Optional[SignedSerializer] = None,
):
"""Verifies that 'delegate' is signed with the required threshold of
keys for the delegated role 'role_name'.
) -> None:
"""Verifies that 'delegated_metadata' is signed with the required
threshold of keys for the delegated role 'delegated_role'.
Args:
role_name: Name of the delegated role to verify
delegate: The Metadata object for the delegated role
delegated_role: Name of the delegated role to verify
delegated_metadata: The Metadata object for the delegated role
signed_serializer: Optional; serializer used for delegate
serialization. Default is CanonicalJSONSerializer.
Expand All @@ -289,38 +289,41 @@ def verify_delegate(
threshold of keys for 'role_name'
"""

# Find the keys and role in our metadata
# Find the keys and role in delegator metadata
role = None
if isinstance(self.signed, Root):
keys = self.signed.keys
role = self.signed.roles.get(role_name)
role = self.signed.roles.get(delegated_role)
elif isinstance(self.signed, Targets):
if self.signed.delegations:
keys = self.signed.delegations.keys
# Assume role names are unique in delegations.roles: #1426
roles = self.signed.delegations.roles
role = next((r for r in roles if r.name == role_name), None)
if self.signed.delegations is None:
raise ValueError(f"No delegation found for {delegated_role}")

keys = self.signed.delegations.keys
roles = self.signed.delegations.roles
# Assume role names are unique in delegations.roles: #1426
# Find first role in roles with matching name (or None if no match)
role = next((r for r in roles if r.name == delegated_role), None)
else:
raise TypeError("Call is valid only on delegator metadata")

if role is None:
raise ValueError(f"No delegation found for {role_name}")
raise ValueError(f"No delegation found for {delegated_role}")

# verify that delegate is signed by required threshold of unique keys
# verify that delegated_metadata is signed by threshold of unique keys
signing_keys = set()
for keyid in role.keyids:
key = keys[keyid]
try:
key.verify_signature(delegate, signed_serializer)
key.verify_signature(delegated_metadata, signed_serializer)
signing_keys.add(key.keyid)
except exceptions.UnsignedMetadataError:
logger.info("Key %s failed to verify %s", keyid, role_name)
logger.info("Key %s failed to verify %s", keyid, delegated_role)

if len(signing_keys) < role.threshold:
raise exceptions.UnsignedMetadataError(
f"{role_name} was signed by {len(signing_keys)}/"
f"{delegated_role} was signed by {len(signing_keys)}/"
f"{role.threshold} keys",
delegate.signed,
delegated_metadata.signed,
)


Expand Down

0 comments on commit 271d5b7

Please sign in to comment.