Skip to content

Commit

Permalink
Merge pull request #1272 from MVrachev/signer-interface
Browse files Browse the repository at this point in the history
Make new api compatible with the Signing interface
  • Loading branch information
lukpueh authored Mar 10, 2021
2 parents 3b33deb + 49aa0fc commit 65005cf
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 16 deletions.
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
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'):
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
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

0 comments on commit 65005cf

Please sign in to comment.