Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make new api compatible with the Signing interface #1272

Merged
merged 1 commit into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']),
Expand Down
12 changes: 9 additions & 3 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
format_keyval_to_metadata
)

from securesystemslib.signer import (
SSlibSigner
)

logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -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.
Expand All @@ -173,16 +178,17 @@ 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.
self.assertTrue(metadata_obj.verify(
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(
Expand Down
32 changes: 20 additions & 12 deletions tuf/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-ordered imports alphabetically.

from securesystemslib.storage import (StorageBackendInterface,
FilesystemBackend)
from securesystemslib.keys import create_signature, verify_signature

from tuf.api.serialization import (MetadataSerializer, MetadataDeserializer,
SignedSerializer)
Expand Down Expand Up @@ -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'):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now popping the signatures list for consistently destructing the passed dictionary as described in the newly added "Side Effect" docstring section.

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(
Expand Down Expand Up @@ -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()
}

Expand Down Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did s/singer/signer to fix a typo I had missed in my review.

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.
Expand All @@ -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)
Expand Down Expand Up @@ -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(
Expand All @@ -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))


Expand Down