From a5e64e133d8e705ea5398b00d6e2f5d936bbf19c Mon Sep 17 00:00:00 2001 From: Martin Vrachev Date: Wed, 3 Feb 2021 18:46:02 +0200 Subject: [PATCH] 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 --- tests/test_api.py | 11 ++++++++--- tuf/api/metadata.py | 28 ++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index edc9aa9010..87a816d69e 100755 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -46,6 +46,9 @@ def setUpModule(): from securesystemslib.keys import ( format_keyval_to_metadata ) + from securesystemslib.signer import ( + SSlibSigner + ) logger = logging.getLogger(__name__) @@ -163,8 +166,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 +177,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 +187,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 a747be6d13..51c42db145 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -19,7 +19,8 @@ persist_temp_file ) from securesystemslib.storage import StorageBackendInterface -from securesystemslib.keys import create_signature, verify_signature +from securesystemslib.keys import verify_signature +from securesystemslib.signer import Signer, SSlibSigner, Signature import tuf.formats import tuf.exceptions @@ -92,12 +93,17 @@ class also that has a 'from_dict' factory method. (Currently this is else: raise ValueError(f'unrecognized metadata type "{_type}"') + signatures = [] + for signature in metadata['signatures']: + new_signature = Signature(signature['keyid'], signature['sig']) + signatures.append(new_signature) + # 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 intead. return cls( signed=inner_cls.from_dict(metadata['signed']), - signatures=metadata['signatures']) + signatures=signatures) @classmethod @@ -146,8 +152,13 @@ def from_json_file( # Serialization. def to_dict(self) -> JsonDict: """Returns the JSON-serializable dictionary representation of self. """ + + signatures_arr = [] + for sig in self.signatures: + signatures_arr.append(sig.to_dict()) + return { - 'signatures': self.signatures, + 'signatures': signatures_arr, 'signed': self.signed.to_dict() } @@ -184,11 +195,12 @@ def to_json_file( # Signatures. - def sign(self, key: JsonDict, append: bool = False) -> JsonDict: + def sign(self, signer: Signer, append: bool = False) -> JsonDict: """Creates signature over 'signed' and assigns it to 'signatures'. Arguments: - key: A securesystemslib-style private key object used for signing. + singer: 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. @@ -203,7 +215,7 @@ def sign(self, key: JsonDict, append: bool = False) -> JsonDict: A securesystemslib-style signature object. """ - signature = create_signature(key, self.signed.to_canonical_bytes()) + signature = signer.sign(self.signed.to_canonical_bytes()) if append: self.signatures.append(signature) @@ -232,7 +244,7 @@ def verify(self, key: JsonDict) -> bool: """ 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( @@ -244,7 +256,7 @@ def verify(self, key: JsonDict) -> bool: f'{key["keyid"]}, not sure which one to verify.') return verify_signature( - key, signatures_for_keyid[0], + key, signatures_for_keyid[0].to_dict(), self.signed.to_canonical_bytes())