Skip to content

Commit 55f6824

Browse files
jkuLukas Puehringer
authored andcommitted
Move verify_delegate() to Root/Targets
This makes logical sense and makes a lot of code using verify_delegate() a little easier since there is no need to keep a reference to the containing metadata anymore. The implementation is in practice in a new class but that's an implementation detail that allows sharing between Targets and Root. Signed-off-by: Jussi Kukkonen <jkukkonen@google.com>
1 parent 12d0c3c commit 55f6824

1 file changed

Lines changed: 84 additions & 48 deletions

File tree

tuf/api/metadata.py

Lines changed: 84 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -395,56 +395,16 @@ def verify_delegate(
395395
"""Verify that ``delegated_metadata`` is signed with the required
396396
threshold of keys for the delegated role ``delegated_role``.
397397
398-
Args:
399-
delegated_role: Name of the delegated role to verify
400-
delegated_metadata: ``Metadata`` object for the delegated role
401-
signed_serializer: Serializer used for delegate
402-
serialization. Default is ``CanonicalJSONSerializer``.
403-
404-
Raises:
405-
UnsignedMetadataError: ``delegated_role`` was not signed with
406-
required threshold of keys for ``role_name``.
407-
ValueError: no delegation was found for ``delegated_role``.
408-
TypeError: called this function on non-delegating metadata class.
398+
.. deprecated:: 2.2.0
399+
Please use ``Root.verify_delegate()`` or ``Targets.verify_delegate()``.
409400
"""
410401

411402
if self.signed.type not in ["root", "targets"]:
412403
raise TypeError("Call is valid only on delegator metadata")
413404

414-
if signed_serializer is None:
415-
# pylint: disable=import-outside-toplevel
416-
from tuf.api.serialization.json import CanonicalJSONSerializer
417-
418-
signed_serializer = CanonicalJSONSerializer()
419-
420-
data = signed_serializer.serialize(delegated_metadata.signed)
421-
role = self.signed.get_delegated_role(delegated_role)
422-
423-
# verify that delegated_metadata is signed by threshold of unique keys
424-
signing_keys = set()
425-
for keyid in role.keyids:
426-
try:
427-
key = self.signed.get_key(keyid)
428-
except ValueError:
429-
logger.info("No key for keyid %s", keyid)
430-
continue
431-
432-
if keyid not in delegated_metadata.signatures:
433-
logger.info("No signature for keyid %s", keyid)
434-
continue
435-
436-
sig = delegated_metadata.signatures[keyid]
437-
try:
438-
key.verify_signature(sig, data)
439-
signing_keys.add(keyid)
440-
except sslib_exceptions.UnverifiedSignatureError:
441-
logger.info("Key %s failed to verify %s", keyid, delegated_role)
442-
443-
if len(signing_keys) < role.threshold:
444-
raise UnsignedMetadataError(
445-
f"{delegated_role} was signed by {len(signing_keys)}/"
446-
f"{role.threshold} keys",
447-
)
405+
self.signed.verify_delegate(
406+
delegated_role, delegated_metadata, signed_serializer
407+
)
448408

449409

450410
class Signed(metaclass=abc.ABCMeta):
@@ -674,7 +634,83 @@ def to_dict(self) -> Dict[str, Any]:
674634
}
675635

676636

677-
class Root(Signed):
637+
class _Delegator(metaclass=abc.ABCMeta):
638+
"""Class that implements verify_delegate() for Root and Targets"""
639+
640+
@abc.abstractmethod
641+
def get_delegated_role(self, delegated_role: str) -> Role:
642+
"""Return the role object for the given delegated role.
643+
644+
Raises ValueError if delegated_role is not actually delegated.
645+
"""
646+
raise NotImplementedError
647+
648+
@abc.abstractmethod
649+
def get_key(self, keyid: str) -> Key:
650+
"""Return the key object for the given keyid.
651+
652+
Raises ValueError if key is not found.
653+
"""
654+
raise NotImplementedError
655+
656+
def verify_delegate(
657+
self,
658+
delegated_role: str,
659+
delegated_metadata: "Metadata",
660+
signed_serializer: Optional[SignedSerializer] = None,
661+
) -> None:
662+
"""Verify that ``delegated_metadata`` is signed with the required
663+
threshold of keys for the delegated role ``delegated_role``.
664+
665+
Args:
666+
delegated_role: Name of the delegated role to verify
667+
delegated_metadata: ``Metadata`` object for the delegated role
668+
signed_serializer: Serializer used for delegate
669+
serialization. Default is ``CanonicalJSONSerializer``.
670+
671+
Raises:
672+
UnsignedMetadataError: ``delegated_role`` was not signed with
673+
required threshold of keys for ``role_name``.
674+
ValueError: no delegation was found for ``delegated_role``.
675+
"""
676+
677+
if signed_serializer is None:
678+
# pylint: disable=import-outside-toplevel
679+
from tuf.api.serialization.json import CanonicalJSONSerializer
680+
681+
signed_serializer = CanonicalJSONSerializer()
682+
683+
data = signed_serializer.serialize(delegated_metadata.signed)
684+
role = self.get_delegated_role(delegated_role)
685+
686+
# verify that delegated_metadata is signed by threshold of unique keys
687+
signing_keys = set()
688+
for keyid in role.keyids:
689+
try:
690+
key = self.get_key(keyid)
691+
except ValueError:
692+
logger.info("No key for keyid %s", keyid)
693+
continue
694+
695+
if keyid not in delegated_metadata.signatures:
696+
logger.info("No signature for keyid %s", keyid)
697+
continue
698+
699+
sig = delegated_metadata.signatures[keyid]
700+
try:
701+
key.verify_signature(sig, data)
702+
signing_keys.add(keyid)
703+
except sslib_exceptions.UnverifiedSignatureError:
704+
logger.info("Key %s failed to verify %s", keyid, delegated_role)
705+
706+
if len(signing_keys) < role.threshold:
707+
raise UnsignedMetadataError(
708+
f"{delegated_role} was signed by {len(signing_keys)}/"
709+
f"{role.threshold} keys",
710+
)
711+
712+
713+
class Root(Signed, _Delegator):
678714
"""A container for the signed part of root metadata.
679715
680716
Parameters listed below are also instance attributes.
@@ -1748,7 +1784,7 @@ def get_prefixed_paths(self) -> List[str]:
17481784
return paths
17491785

17501786

1751-
class Targets(Signed):
1787+
class Targets(Signed, _Delegator):
17521788
"""A container for the signed part of targets metadata.
17531789
17541790
Targets contains verifying information about target files and also
@@ -1925,7 +1961,7 @@ def get_delegated_role(self, delegated_role: str) -> Role:
19251961
def get_key(self, keyid: str) -> Key:
19261962
"""Return the key object for the given keyid.
19271963
1928-
Raises ValueError if keyid is not found.
1964+
Raises ValueError if key is not found.
19291965
"""
19301966
if self.delegations is None:
19311967
raise ValueError("No delegations found")

0 commit comments

Comments
 (0)