diff --git a/setup.py b/setup.py index 7984d2d662..10aa219248 100755 --- a/setup.py +++ b/setup.py @@ -113,7 +113,7 @@ python_requires="~=3.6", install_requires = [ 'requests>=2.19.1', - 'securesystemslib>=0.18.0', + 'securesystemslib>=0.20.0', 'six>=1.11.0' ], packages = find_packages(exclude=['tests']), diff --git a/tests/test_api.py b/tests/test_api.py index e13c704242..24f6ace24a 100755 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -47,6 +47,10 @@ format_keyval_to_metadata ) +from securesystemslib.signer import ( + SSlibSigner +) + logger = logging.getLogger(__name__) @@ -163,8 +167,9 @@ def test_sign_verify(self): self.assertTrue(metadata_obj.verify( self.keystore['targets']['public'])) + sslib_signer = SSlibSigner(self.keystore['snapshot']['private']) # Append a new signature with the unrelated key and assert that ... - metadata_obj.sign(self.keystore['snapshot']['private'], append=True) + metadata_obj.sign(sslib_signer, append=True) # ... there are now two signatures, and self.assertTrue(len(metadata_obj.signatures) == 2) # ... both are valid for the corresponding keys. @@ -173,8 +178,9 @@ def test_sign_verify(self): self.assertTrue(metadata_obj.verify( self.keystore['snapshot']['public'])) + sslib_signer.key_dict = self.keystore['timestamp']['private'] # Create and assign (don't append) a new signature and assert that ... - metadata_obj.sign(self.keystore['timestamp']['private'], append=False) + metadata_obj.sign(sslib_signer, append=False) # ... there now is only one signature, self.assertTrue(len(metadata_obj.signatures) == 1) # ... valid for that key. @@ -182,7 +188,7 @@ def test_sign_verify(self): self.keystore['timestamp']['public'])) # Assert exception if there are more than one signatures for a key - metadata_obj.sign(self.keystore['timestamp']['private'], append=True) + metadata_obj.sign(sslib_signer, append=True) with self.assertRaises(tuf.exceptions.Error) as ctx: metadata_obj.verify(self.keystore['timestamp']['public']) self.assertTrue( diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index 1209577457..afd45c64f7 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -20,10 +20,11 @@ import tempfile +from securesystemslib.keys import verify_signature from securesystemslib.util import persist_temp_file +from securesystemslib.signer import Signer, Signature from securesystemslib.storage import (StorageBackendInterface, FilesystemBackend) -from securesystemslib.keys import create_signature, verify_signature from tuf.api.serialization import (MetadataSerializer, MetadataDeserializer, SignedSerializer) @@ -90,12 +91,14 @@ def from_dict(cls, metadata: Mapping[str, Any]) -> 'Metadata': else: raise ValueError(f'unrecognized metadata type "{_type}"') - # NOTE: If Signature becomes a class, we should iterate over - # metadata['signatures'], call Signature.from_dict for each item, and - # pass a list of Signature objects to the Metadata constructor instead. + signatures = [] + for signature in metadata.pop('signatures'): + signature_obj = Signature.from_dict(signature) + signatures.append(signature_obj) + return cls( signed=inner_cls.from_dict(metadata.pop('signed')), - signatures=metadata.pop('signatures')) + signatures=signatures) @classmethod def from_file( @@ -139,8 +142,13 @@ def from_file( def to_dict(self) -> Dict[str, Any]: """Returns the dict representation of self. """ + + signatures = [] + for sig in self.signatures: + signatures.append(sig.to_dict()) + return { - 'signatures': self.signatures, + 'signatures': signatures, 'signed': self.signed.to_dict() } @@ -178,13 +186,14 @@ def to_file( # Signatures. def sign( - self, key: Mapping[str, Any], append: bool = False, + self, signer: Signer, append: bool = False, signed_serializer: Optional[SignedSerializer] = None ) -> Dict[str, Any]: """Creates signature over 'signed' and assigns it to 'signatures'. Arguments: - key: A securesystemslib-style private key object used for signing. + signer: An object implementing the securesystemslib.signer.Signer + interface. append: A boolean indicating if the signature should be appended to the list of signatures or replace any existing signatures. The default behavior is to replace signatures. @@ -209,8 +218,7 @@ def sign( from tuf.api.serialization.json import CanonicalJSONSerializer signed_serializer = CanonicalJSONSerializer() - signature = create_signature(key, - signed_serializer.serialize(self.signed)) + signature = signer.sign(signed_serializer.serialize(self.signed)) if append: self.signatures.append(signature) @@ -244,7 +252,7 @@ def verify(self, key: Mapping[str, Any], """ signatures_for_keyid = list(filter( - lambda sig: sig['keyid'] == key['keyid'], self.signatures)) + lambda sig: sig.keyid == key['keyid'], self.signatures)) if not signatures_for_keyid: raise tuf.exceptions.Error( @@ -262,7 +270,7 @@ def verify(self, key: Mapping[str, Any], signed_serializer = CanonicalJSONSerializer() return verify_signature( - key, signatures_for_keyid[0], + key, signatures_for_keyid[0].to_dict(), signed_serializer.serialize(self.signed))