Make new API compatible with the Signing interface

In the securesystemslib pr https://github.com/secure-systems-lab/securesystemslib/pull/319
I added a new Signer interface with the purpose of supporting multiple
signing implementations.
Additionally, I added the SSlibSigner implementation of that interface
which implements the signing operation for rsa, ed25519 and ecdsa
schemes.
With this commit, I integrate the SSlibSigner into the new API in tuf.

Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
This commit is contained in:
Martin Vrachev 2021-02-03 18:46:02 +02:00 committed by Lukas Puehringer
parent 3b33deb26b
commit 49aa0fc167
3 changed files with 30 additions and 16 deletions

View file

@ -113,7 +113,7 @@
python_requires="~=3.6", python_requires="~=3.6",
install_requires = [ install_requires = [
'requests>=2.19.1', 'requests>=2.19.1',
'securesystemslib>=0.18.0', 'securesystemslib>=0.20.0',
'six>=1.11.0' 'six>=1.11.0'
], ],
packages = find_packages(exclude=['tests']), packages = find_packages(exclude=['tests']),

View file

@ -47,6 +47,10 @@
format_keyval_to_metadata format_keyval_to_metadata
) )
from securesystemslib.signer import (
SSlibSigner
)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -163,8 +167,9 @@ def test_sign_verify(self):
self.assertTrue(metadata_obj.verify( self.assertTrue(metadata_obj.verify(
self.keystore['targets']['public'])) self.keystore['targets']['public']))
sslib_signer = SSlibSigner(self.keystore['snapshot']['private'])
# Append a new signature with the unrelated key and assert that ... # 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 # ... there are now two signatures, and
self.assertTrue(len(metadata_obj.signatures) == 2) self.assertTrue(len(metadata_obj.signatures) == 2)
# ... both are valid for the corresponding keys. # ... both are valid for the corresponding keys.
@ -173,8 +178,9 @@ def test_sign_verify(self):
self.assertTrue(metadata_obj.verify( self.assertTrue(metadata_obj.verify(
self.keystore['snapshot']['public'])) self.keystore['snapshot']['public']))
sslib_signer.key_dict = self.keystore['timestamp']['private']
# Create and assign (don't append) a new signature and assert that ... # 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, # ... there now is only one signature,
self.assertTrue(len(metadata_obj.signatures) == 1) self.assertTrue(len(metadata_obj.signatures) == 1)
# ... valid for that key. # ... valid for that key.
@ -182,7 +188,7 @@ def test_sign_verify(self):
self.keystore['timestamp']['public'])) self.keystore['timestamp']['public']))
# Assert exception if there are more than one signatures for a key # 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: with self.assertRaises(tuf.exceptions.Error) as ctx:
metadata_obj.verify(self.keystore['timestamp']['public']) metadata_obj.verify(self.keystore['timestamp']['public'])
self.assertTrue( self.assertTrue(

View file

@ -20,10 +20,11 @@
import tempfile import tempfile
from securesystemslib.keys import verify_signature
from securesystemslib.util import persist_temp_file from securesystemslib.util import persist_temp_file
from securesystemslib.signer import Signer, Signature
from securesystemslib.storage import (StorageBackendInterface, from securesystemslib.storage import (StorageBackendInterface,
FilesystemBackend) FilesystemBackend)
from securesystemslib.keys import create_signature, verify_signature
from tuf.api.serialization import (MetadataSerializer, MetadataDeserializer, from tuf.api.serialization import (MetadataSerializer, MetadataDeserializer,
SignedSerializer) SignedSerializer)
@ -90,12 +91,14 @@ def from_dict(cls, metadata: Mapping[str, Any]) -> 'Metadata':
else: else:
raise ValueError(f'unrecognized metadata type "{_type}"') raise ValueError(f'unrecognized metadata type "{_type}"')
# NOTE: If Signature becomes a class, we should iterate over signatures = []
# metadata['signatures'], call Signature.from_dict for each item, and for signature in metadata.pop('signatures'):
# pass a list of Signature objects to the Metadata constructor instead. signature_obj = Signature.from_dict(signature)
signatures.append(signature_obj)
return cls( return cls(
signed=inner_cls.from_dict(metadata.pop('signed')), signed=inner_cls.from_dict(metadata.pop('signed')),
signatures=metadata.pop('signatures')) signatures=signatures)
@classmethod @classmethod
def from_file( def from_file(
@ -139,8 +142,13 @@ def from_file(
def to_dict(self) -> Dict[str, Any]: def to_dict(self) -> Dict[str, Any]:
"""Returns the dict representation of self. """ """Returns the dict representation of self. """
signatures = []
for sig in self.signatures:
signatures.append(sig.to_dict())
return { return {
'signatures': self.signatures, 'signatures': signatures,
'signed': self.signed.to_dict() 'signed': self.signed.to_dict()
} }
@ -178,13 +186,14 @@ def to_file(
# Signatures. # Signatures.
def sign( def sign(
self, key: Mapping[str, Any], append: bool = False, self, signer: Signer, append: bool = False,
signed_serializer: Optional[SignedSerializer] = None signed_serializer: Optional[SignedSerializer] = None
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Creates signature over 'signed' and assigns it to 'signatures'. """Creates signature over 'signed' and assigns it to 'signatures'.
Arguments: 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 append: A boolean indicating if the signature should be appended to
the list of signatures or replace any existing signatures. The the list of signatures or replace any existing signatures. The
default behavior is to replace signatures. default behavior is to replace signatures.
@ -209,8 +218,7 @@ def sign(
from tuf.api.serialization.json import CanonicalJSONSerializer from tuf.api.serialization.json import CanonicalJSONSerializer
signed_serializer = CanonicalJSONSerializer() signed_serializer = CanonicalJSONSerializer()
signature = create_signature(key, signature = signer.sign(signed_serializer.serialize(self.signed))
signed_serializer.serialize(self.signed))
if append: if append:
self.signatures.append(signature) self.signatures.append(signature)
@ -244,7 +252,7 @@ def verify(self, key: Mapping[str, Any],
""" """
signatures_for_keyid = list(filter( 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: if not signatures_for_keyid:
raise tuf.exceptions.Error( raise tuf.exceptions.Error(
@ -262,7 +270,7 @@ def verify(self, key: Mapping[str, Any],
signed_serializer = CanonicalJSONSerializer() signed_serializer = CanonicalJSONSerializer()
return verify_signature( return verify_signature(
key, signatures_for_keyid[0], key, signatures_for_keyid[0].to_dict(),
signed_serializer.serialize(self.signed)) signed_serializer.serialize(self.signed))