Skip to content

Commit

Permalink
Make new API compatible with the Signing interface
Browse files Browse the repository at this point in the history
In the securesystemslib pr secure-systems-lab/securesystemslib#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>
  • Loading branch information
MVrachev committed Feb 26, 2021
1 parent 74e1b0f commit a5e64e1
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 11 deletions.
11 changes: 8 additions & 3 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ def setUpModule():
from securesystemslib.keys import (
format_keyval_to_metadata
)
from securesystemslib.signer import (
SSlibSigner
)

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -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.
Expand All @@ -173,16 +177,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
28 changes: 20 additions & 8 deletions tuf/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
}

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


Expand Down

0 comments on commit a5e64e1

Please sign in to comment.