Skip to content
Merged
2 changes: 0 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@
# -- Autodoc configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html

autodoc_mock_imports = ["securesystemslib"]

# Tone down the "tuf.api.metadata." repetition
add_module_names = False
python_use_unqualified_type_names = True
Expand Down
11 changes: 5 additions & 6 deletions examples/manual_repo/basic_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,12 @@
from typing import Any, Dict

from securesystemslib.keys import generate_ed25519_key
from securesystemslib.signer import SSlibSigner
from securesystemslib.signer import SSlibKey, SSlibSigner

from tuf.api.metadata import (
SPECIFICATION_VERSION,
DelegatedRole,
Delegations,
Key,
Metadata,
MetaFile,
Root,
Expand Down Expand Up @@ -157,7 +156,7 @@ def _in(days: float) -> datetime:
for name in ["targets", "snapshot", "timestamp", "root"]:
keys[name] = generate_ed25519_key()
roles["root"].signed.add_key(
Key.from_securesystemslib_key(keys[name]), name
SSlibKey.from_securesystemslib_key(keys[name]), name
)

# NOTE: We only need the public part to populate root, so it is possible to use
Expand All @@ -173,7 +172,7 @@ def _in(days: float) -> datetime:
# required signature threshold.
another_root_key = generate_ed25519_key()
roles["root"].signed.add_key(
Key.from_securesystemslib_key(another_root_key), "root"
SSlibKey.from_securesystemslib_key(another_root_key), "root"
)
roles["root"].signed.roles["root"].threshold = 2

Expand Down Expand Up @@ -271,7 +270,7 @@ def _in(days: float) -> datetime:
# https://theupdateframework.github.io/specification/latest/#delegations
roles["targets"].signed.delegations = Delegations(
keys={
keys[delegatee_name]["keyid"]: Key.from_securesystemslib_key(
keys[delegatee_name]["keyid"]: SSlibKey.from_securesystemslib_key(
keys[delegatee_name]
)
},
Expand Down Expand Up @@ -345,7 +344,7 @@ def _in(days: float) -> datetime:

roles["root"].signed.revoke_key(keys["root"]["keyid"], "root")
roles["root"].signed.add_key(
Key.from_securesystemslib_key(new_root_key), "root"
SSlibKey.from_securesystemslib_key(new_root_key), "root"
)
roles["root"].signed.version += 1

Expand Down
5 changes: 2 additions & 3 deletions examples/manual_repo/hashed_bin_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@
from typing import Any, Dict, Iterator, List, Tuple

from securesystemslib.keys import generate_ed25519_key
from securesystemslib.signer import SSlibSigner
from securesystemslib.signer import SSlibKey, SSlibSigner

from tuf.api.metadata import (
DelegatedRole,
Delegations,
Key,
Metadata,
TargetFile,
Targets,
Expand Down Expand Up @@ -146,7 +145,7 @@ def find_hash_bin(path: str) -> str:
# Create preliminary delegating targets role (bins) and add public key for
# delegated targets (bin_n) to key store. Delegation details are update below.
roles["bins"] = Metadata(Targets(expires=_in(365)))
bin_n_key = Key.from_securesystemslib_key(keys["bin-n"])
bin_n_key = SSlibKey.from_securesystemslib_key(keys["bin-n"])
roles["bins"].signed.delegations = Delegations(
keys={bin_n_key.keyid: bin_n_key},
roles={},
Expand Down
4 changes: 2 additions & 2 deletions examples/manual_repo/succinct_hash_bin_delegations.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from typing import Dict, Tuple

from securesystemslib.keys import generate_ed25519_key
from securesystemslib.signer import SSlibSigner
from securesystemslib.signer import SSlibKey, SSlibSigner

from tuf.api.metadata import (
Delegations,
Expand Down Expand Up @@ -82,7 +82,7 @@
def create_key() -> Tuple[Key, SSlibSigner]:
"""Generates a new Key and Signer."""
sslib_key = generate_ed25519_key()
return Key.from_securesystemslib_key(sslib_key), SSlibSigner(sslib_key)
return SSlibKey.from_securesystemslib_key(sslib_key), SSlibSigner(sslib_key)


# Create one signing key for all bins, and one for the delegating targets role.
Expand Down
5 changes: 2 additions & 3 deletions examples/repository/_simplerepo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
from typing import Dict, List

from securesystemslib import keys
from securesystemslib.signer import Signer, SSlibSigner
from securesystemslib.signer import Signer, SSlibKey, SSlibSigner

from tuf.api.metadata import (
Key,
Metadata,
MetaFile,
Root,
Expand Down Expand Up @@ -72,7 +71,7 @@ def __init__(self) -> None:
for role in ["root", "timestamp", "snapshot", "targets"]:
key = keys.generate_ed25519_key()
self.signer_cache[role].append(SSlibSigner(key))
root.add_key(Key.from_securesystemslib_key(key), role)
root.add_key(SSlibKey.from_securesystemslib_key(key), role)

for role in ["timestamp", "snapshot", "targets"]:
with self.edit(role):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ classifiers = [
]
dependencies = [
"requests>=2.19.1",
"securesystemslib>=0.22.0",
"securesystemslib>=0.26.0",
]
dynamic = ["version"]

Expand Down
4 changes: 2 additions & 2 deletions tests/generated_data/generate_md.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from datetime import datetime
from typing import Dict, List, Optional

from securesystemslib.signer import SSlibSigner
from securesystemslib.signer import SSlibKey, SSlibSigner

from tests import utils
from tuf.api.metadata import Key, Metadata, Root, Snapshot, Targets, Timestamp
Expand Down Expand Up @@ -36,7 +36,7 @@

keys: Dict[str, Key] = {}
for index in range(4):
keys[f"ed25519_{index}"] = Key.from_securesystemslib_key(
keys[f"ed25519_{index}"] = SSlibKey.from_securesystemslib_key(
{
"keytype": "ed25519",
"scheme": "ed25519",
Expand Down
6 changes: 3 additions & 3 deletions tests/repository_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

import securesystemslib.hash as sslib_hash
from securesystemslib.keys import generate_ed25519_key
from securesystemslib.signer import SSlibSigner
from securesystemslib.signer import SSlibKey, SSlibSigner

from tuf.api.exceptions import DownloadHTTPError
from tuf.api.metadata import (
Expand Down Expand Up @@ -156,8 +156,8 @@ def all_targets(self) -> Iterator[Tuple[str, Targets]]:

@staticmethod
def create_key() -> Tuple[Key, SSlibSigner]:
sslib_key = generate_ed25519_key()
return Key.from_securesystemslib_key(sslib_key), SSlibSigner(sslib_key)
key = generate_ed25519_key()
return SSlibKey.from_securesystemslib_key(key), SSlibSigner(key)

def add_signer(self, role: str, signer: SSlibSigner) -> None:
if role not in self.signers:
Expand Down
90 changes: 46 additions & 44 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
from datetime import datetime, timedelta
from typing import Any, ClassVar, Dict

from securesystemslib import exceptions as sslib_exceptions
from securesystemslib import hash as sslib_hash
from securesystemslib.interface import (
import_ed25519_privatekey_from_file,
import_ed25519_publickey_from_file,
)
from securesystemslib.keys import generate_ed25519_key
from securesystemslib.signer import Signature, SSlibSigner
from securesystemslib.signer import SSlibKey, SSlibSigner

from tests import utils
from tuf.api import exceptions
Expand All @@ -34,6 +35,7 @@
Key,
Metadata,
Root,
Signature,
Snapshot,
SuccinctRoles,
TargetFile,
Expand Down Expand Up @@ -187,8 +189,8 @@ def test_to_from_bytes(self) -> None:
self.assertEqual(metadata_obj_2.to_bytes(), obj_bytes)

def test_sign_verify(self) -> None:
root_path = os.path.join(self.repo_dir, "metadata", "root.json")
root = Metadata[Root].from_file(root_path).signed
path = os.path.join(self.repo_dir, "metadata")
root = Metadata[Root].from_file(os.path.join(path, "root.json")).signed

# Locate the public keys we need from root
targets_keyid = next(iter(root.roles[Targets.type].keyids))
Expand All @@ -199,41 +201,37 @@ def test_sign_verify(self) -> None:
timestamp_key = root.keys[timestamp_keyid]

# Load sample metadata (targets) and assert ...
path = os.path.join(self.repo_dir, "metadata", "targets.json")
md_obj = Metadata.from_file(path)
md_obj = Metadata.from_file(os.path.join(path, "targets.json"))
sig = md_obj.signatures[targets_keyid]
data = CanonicalJSONSerializer().serialize(md_obj.signed)

# ... it has a single existing signature,
self.assertEqual(len(md_obj.signatures), 1)
# ... which is valid for the correct key.
targets_key.verify_signature(md_obj)
with self.assertRaises(exceptions.UnsignedMetadataError):
snapshot_key.verify_signature(md_obj)

# Test verifying with explicitly set serializer
targets_key.verify_signature(md_obj, CanonicalJSONSerializer())
with self.assertRaises(exceptions.UnsignedMetadataError):
targets_key.verify_signature(md_obj, JSONSerializer()) # type: ignore[arg-type]
targets_key.verify_signature(sig, data)
with self.assertRaises(sslib_exceptions.VerificationError):
snapshot_key.verify_signature(sig, data)

sslib_signer = SSlibSigner(self.keystore[Snapshot.type])
# Append a new signature with the unrelated key and assert that ...
sig = md_obj.sign(sslib_signer, append=True)
snapshot_sig = md_obj.sign(sslib_signer, append=True)
# ... there are now two signatures, and
self.assertEqual(len(md_obj.signatures), 2)
# ... both are valid for the corresponding keys.
targets_key.verify_signature(md_obj)
snapshot_key.verify_signature(md_obj)
targets_key.verify_signature(sig, data)
snapshot_key.verify_signature(snapshot_sig, data)
# ... the returned (appended) signature is for snapshot key
self.assertEqual(sig.keyid, snapshot_keyid)
self.assertEqual(snapshot_sig.keyid, snapshot_keyid)

sslib_signer = SSlibSigner(self.keystore[Timestamp.type])
# Create and assign (don't append) a new signature and assert that ...
md_obj.sign(sslib_signer, append=False)
ts_sig = md_obj.sign(sslib_signer, append=False)
# ... there now is only one signature,
self.assertEqual(len(md_obj.signatures), 1)
# ... valid for that key.
timestamp_key.verify_signature(md_obj)
with self.assertRaises(exceptions.UnsignedMetadataError):
targets_key.verify_signature(md_obj)
timestamp_key.verify_signature(ts_sig, data)
with self.assertRaises(sslib_exceptions.VerificationError):
targets_key.verify_signature(ts_sig, data)

def test_sign_failures(self) -> None:
# Test throwing UnsignedMetadataError because of signing problems
Expand All @@ -248,7 +246,7 @@ def test_sign_failures(self) -> None:
with self.assertRaises(exceptions.UnsignedMetadataError):
md.sign(sslib_signer)

def test_verify_failures(self) -> None:
def test_key_verify_failures(self) -> None:
root_path = os.path.join(self.repo_dir, "metadata", "root.json")
root = Metadata[Root].from_file(root_path).signed

Expand All @@ -259,36 +257,36 @@ def test_verify_failures(self) -> None:
# Load sample metadata (timestamp)
path = os.path.join(self.repo_dir, "metadata", "timestamp.json")
md_obj = Metadata.from_file(path)
sig = md_obj.signatures[timestamp_keyid]
data = CanonicalJSONSerializer().serialize(md_obj.signed)

# Test failure on unknown scheme (securesystemslib
# UnsupportedAlgorithmError)
scheme = timestamp_key.scheme
timestamp_key.scheme = "foo"
with self.assertRaises(exceptions.UnsignedMetadataError):
timestamp_key.verify_signature(md_obj)
with self.assertRaises(sslib_exceptions.VerificationError):
timestamp_key.verify_signature(sig, data)
timestamp_key.scheme = scheme

# Test failure on broken public key data (securesystemslib
# CryptoError)
public = timestamp_key.keyval["public"]
timestamp_key.keyval["public"] = "ffff"
with self.assertRaises(exceptions.UnsignedMetadataError):
timestamp_key.verify_signature(md_obj)
with self.assertRaises(sslib_exceptions.VerificationError):
timestamp_key.verify_signature(sig, data)
timestamp_key.keyval["public"] = public

# Test failure with invalid signature (securesystemslib
# FormatError)
sig = md_obj.signatures[timestamp_keyid]
correct_sig = sig.signature
sig.signature = "foo"
with self.assertRaises(exceptions.UnsignedMetadataError):
timestamp_key.verify_signature(md_obj)
incorrect_sig = copy(sig)
incorrect_sig.signature = "foo"
with self.assertRaises(sslib_exceptions.VerificationError):
timestamp_key.verify_signature(incorrect_sig, data)

# Test failure with valid but incorrect signature
sig.signature = "ff" * 64
with self.assertRaises(exceptions.UnsignedMetadataError):
timestamp_key.verify_signature(md_obj)
sig.signature = correct_sig
incorrect_sig.signature = "ff" * 64
with self.assertRaises(sslib_exceptions.UnverifiedSignatureError):
timestamp_key.verify_signature(incorrect_sig, data)

def test_metadata_signed_is_expired(self) -> None:
# Use of Snapshot is arbitrary, we're just testing the base class
Expand Down Expand Up @@ -355,6 +353,15 @@ def test_metadata_verify_delegate(self) -> None:
root.verify_delegate(Snapshot.type, snapshot)
snapshot.signed.expires = expires

# verify fails if sslib verify fails with VerificationError
# (in this case signature is malformed)
keyid = next(iter(root.signed.roles[Snapshot.type].keyids))
good_sig = snapshot.signatures[keyid].signature
snapshot.signatures[keyid].signature = "foo"
with self.assertRaises(exceptions.UnsignedMetadataError):
root.verify_delegate(Snapshot.type, snapshot)
snapshot.signatures[keyid].signature = good_sig

# verify fails if roles keys do not sign the metadata
with self.assertRaises(exceptions.UnsignedMetadataError):
root.verify_delegate(Timestamp.type, snapshot)
Expand Down Expand Up @@ -382,14 +389,9 @@ def test_key_class(self) -> None:
# Test if from_securesystemslib_key removes the private key from keyval
# of a securesystemslib key dictionary.
sslib_key = generate_ed25519_key()
key = Key.from_securesystemslib_key(sslib_key)
key = SSlibKey.from_securesystemslib_key(sslib_key)
self.assertFalse("private" in key.keyval.keys())

# Test raising ValueError with non-existent keytype
sslib_key["keytype"] = "bad keytype"
with self.assertRaises(ValueError):
Key.from_securesystemslib_key(sslib_key)

def test_root_add_key_and_revoke_key(self) -> None:
root_path = os.path.join(self.repo_dir, "metadata", "root.json")
root = Metadata[Root].from_file(root_path)
Expand All @@ -399,7 +401,7 @@ def test_root_add_key_and_revoke_key(self) -> None:
os.path.join(self.keystore_dir, "root_key2.pub")
)
keyid = root_key2["keyid"]
key_metadata = Key(
key_metadata = SSlibKey(
keyid,
root_key2["keytype"],
root_key2["scheme"],
Expand All @@ -412,7 +414,7 @@ def test_root_add_key_and_revoke_key(self) -> None:

# Assert that add_key with old argument order will raise an error
with self.assertRaises(ValueError):
root.signed.add_key(Root.type, key_metadata) # type: ignore
root.signed.add_key(Root.type, key_metadata)

# Add new root key
root.signed.add_key(key_metadata, Root.type)
Expand Down Expand Up @@ -513,7 +515,7 @@ def test_targets_key_api(self) -> None:

# Assert that add_key with old argument order will raise an error
with self.assertRaises(ValueError):
targets.add_key("role1", key) # type: ignore
targets.add_key("role1", key)

# Assert that delegated role "role1" does not contain the new key
self.assertNotIn(key.keyid, targets.delegations.roles["role1"].keyids)
Expand Down
Loading