mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Metadata API: Fix verify_delegate for new Key API
verify_delegate() unfortunately needs an almost complete rewrite as the Key.verify_signature() API change affects it quite a bit. Refactoring the role and key lookup into a separate method makes the code readable again. Signed-off-by: Jussi Kukkonen <jkukkonen@google.com>
This commit is contained in:
parent
b55ac25cf5
commit
ed0ec03399
2 changed files with 58 additions and 29 deletions
|
|
@ -353,6 +353,15 @@ def test_metadata_verify_delegate(self) -> None:
|
|||
root.verify_delegate(Snapshot.type, snapshot)
|
||||
snapshot.signed.expires = expires
|
||||
|
||||
# verify fails if sslib verify fails with VerificationError
|
||||
# (in this case signature is malformed)
|
||||
keyid = next(iter(root.signed.roles[Snapshot.type].keyids))
|
||||
good_sig = snapshot.signatures[keyid].signature
|
||||
snapshot.signatures[keyid].signature = "foo"
|
||||
with self.assertRaises(exceptions.UnsignedMetadataError):
|
||||
root.verify_delegate(Snapshot.type, snapshot)
|
||||
snapshot.signatures[keyid].signature = good_sig
|
||||
|
||||
# verify fails if roles keys do not sign the metadata
|
||||
with self.assertRaises(exceptions.UnsignedMetadataError):
|
||||
root.verify_delegate(Timestamp.type, snapshot)
|
||||
|
|
|
|||
|
|
@ -386,29 +386,11 @@ def sign(
|
|||
|
||||
return signature
|
||||
|
||||
def verify_delegate(
|
||||
self,
|
||||
delegated_role: str,
|
||||
delegated_metadata: "Metadata",
|
||||
signed_serializer: Optional[SignedSerializer] = None,
|
||||
) -> None:
|
||||
"""Verify that ``delegated_metadata`` is signed with the required
|
||||
threshold of keys for the delegated role ``delegated_role``.
|
||||
def _get_role_and_keys(
|
||||
self, delegated_role: str
|
||||
) -> Tuple["Role", Dict[str, Key]]:
|
||||
"""Return the keys and role for delegated_role"""
|
||||
|
||||
Args:
|
||||
delegated_role: Name of the delegated role to verify
|
||||
delegated_metadata: ``Metadata`` object for the delegated role
|
||||
signed_serializer: Serializer used for delegate
|
||||
serialization. Default is ``CanonicalJSONSerializer``.
|
||||
|
||||
Raises:
|
||||
UnsignedMetadataError: ``delegated_role`` was not signed with
|
||||
required threshold of keys for ``role_name``.
|
||||
ValueError: no delegation was found for ``delegated_role``.
|
||||
TypeError: called this function on non-delegating metadata class.
|
||||
"""
|
||||
|
||||
# Find the keys and role in delegator metadata
|
||||
role: Optional[Role] = None
|
||||
if isinstance(self.signed, Root):
|
||||
keys = self.signed.keys
|
||||
|
|
@ -431,17 +413,55 @@ def verify_delegate(
|
|||
if role is None:
|
||||
raise ValueError(f"No delegation found for {delegated_role}")
|
||||
|
||||
return (role, keys)
|
||||
|
||||
def verify_delegate(
|
||||
self,
|
||||
delegated_role: str,
|
||||
delegated_metadata: "Metadata",
|
||||
signed_serializer: Optional[SignedSerializer] = None,
|
||||
) -> None:
|
||||
"""Verify that ``delegated_metadata`` is signed with the required
|
||||
threshold of keys for the delegated role ``delegated_role``.
|
||||
|
||||
Args:
|
||||
delegated_role: Name of the delegated role to verify
|
||||
delegated_metadata: ``Metadata`` object for the delegated role
|
||||
signed_serializer: Serializer used for delegate
|
||||
serialization. Default is ``CanonicalJSONSerializer``.
|
||||
|
||||
Raises:
|
||||
UnsignedMetadataError: ``delegated_role`` was not signed with
|
||||
required threshold of keys for ``role_name``.
|
||||
ValueError: no delegation was found for ``delegated_role``.
|
||||
TypeError: called this function on non-delegating metadata class.
|
||||
"""
|
||||
|
||||
if signed_serializer is None:
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from tuf.api.serialization.json import CanonicalJSONSerializer
|
||||
|
||||
signed_serializer = CanonicalJSONSerializer()
|
||||
|
||||
data = signed_serializer.serialize(delegated_metadata.signed)
|
||||
role, keys = self._get_role_and_keys(delegated_role)
|
||||
|
||||
# verify that delegated_metadata is signed by threshold of unique keys
|
||||
signing_keys = set()
|
||||
for keyid in role.keyids:
|
||||
key = keys[keyid]
|
||||
if keyid not in keys:
|
||||
logger.info("No key for keyid %s", keyid)
|
||||
continue
|
||||
if keyid not in delegated_metadata.signatures:
|
||||
logger.info("No signature for keyid %s", keyid)
|
||||
continue
|
||||
|
||||
sig = delegated_metadata.signatures[keyid]
|
||||
try:
|
||||
key.verify_signature(delegated_metadata, signed_serializer)
|
||||
signing_keys.add(key.keyid)
|
||||
except UnsignedMetadataError:
|
||||
logger.debug(
|
||||
"Key %s failed to verify %s", keyid, delegated_role
|
||||
)
|
||||
keys[keyid].verify_signature(sig, data)
|
||||
signing_keys.add(keyid)
|
||||
except sslib_exceptions.UnverifiedSignatureError:
|
||||
logger.info("Key %s failed to verify %s", keyid, delegated_role)
|
||||
|
||||
if len(signing_keys) < role.threshold:
|
||||
raise UnsignedMetadataError(
|
||||
|
|
|
|||
Loading…
Reference in a new issue