Skip to content

Commit 0f64cf4

Browse files
author
Lukas Puehringer
committed
tests: add basic tests for dsse support
* Add API tests for SimpleEnvelope This is not as comprehensive as Metadata API. The latter also includes tests for all payload classes, which should cover the same scenarios as if used with SimpleEnvelope. * Add unit test for newly added simple envelope load helper function in trusted metadata set. Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
1 parent 8eb6f08 commit 0f64cf4

2 files changed

Lines changed: 142 additions & 1 deletion

File tree

tests/test_api.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import unittest
1616
from copy import copy, deepcopy
1717
from datetime import datetime, timedelta
18+
from pathlib import Path
1819
from typing import Any, ClassVar, Dict, Optional
1920

2021
from securesystemslib import exceptions as sslib_exceptions
@@ -33,6 +34,7 @@
3334

3435
from tests import utils
3536
from tuf.api import exceptions
37+
from tuf.api.dsse import SimpleEnvelope
3638
from tuf.api.metadata import (
3739
TOP_LEVEL_ROLE_NAMES,
3840
DelegatedRole,
@@ -1144,6 +1146,95 @@ def test_delegations_get_delegated_role(self) -> None:
11441146
)
11451147

11461148

1149+
class TestSimpleEnvelope(unittest.TestCase):
1150+
"""Tests for public API in 'tuf/api/dsse.py'."""
1151+
1152+
@classmethod
1153+
def setUpClass(cls) -> None:
1154+
repo_data_dir = Path(utils.TESTS_DIR) / "repository_data"
1155+
cls.metadata_dir = repo_data_dir / "repository" / "metadata"
1156+
cls.signer_store = {}
1157+
for role in [Snapshot, Targets, Timestamp]:
1158+
key_path = repo_data_dir / "keystore" / f"{role.type}_key"
1159+
key = import_ed25519_privatekey_from_file(
1160+
str(key_path),
1161+
password="password",
1162+
)
1163+
cls.signer_store[role.type] = SSlibSigner(key)
1164+
1165+
def test_serialization(self) -> None:
1166+
"""Basic de/serialization test.
1167+
1168+
1. Load test metadata for each role
1169+
2. Wrap metadata payloads in envelope serializing the payload
1170+
3. Serialize envelope
1171+
4. De-serialize envelope
1172+
5. De-serialize payload
1173+
1174+
"""
1175+
for role in [Root, Timestamp, Snapshot, Targets]:
1176+
metadata_path = self.metadata_dir / f"{role.type}.json"
1177+
metadata = Metadata.from_file(str(metadata_path))
1178+
self.assertIsInstance(metadata.signed, role)
1179+
1180+
envelope = SimpleEnvelope.from_signed(metadata.signed)
1181+
envelope_bytes = envelope.to_bytes()
1182+
1183+
envelope2 = SimpleEnvelope.from_bytes(envelope_bytes)
1184+
payload = envelope2.get_signed()
1185+
self.assertEqual(metadata.signed, payload)
1186+
1187+
def test_fail_envelope_serialization(self) -> None:
1188+
envelope = SimpleEnvelope(b"foo", "bar", ["baz"])
1189+
with self.assertRaises(SerializationError):
1190+
envelope.to_bytes()
1191+
1192+
def test_fail_envelope_deserialization(self) -> None:
1193+
with self.assertRaises(DeserializationError):
1194+
SimpleEnvelope.from_bytes(b"[")
1195+
1196+
def test_fail_payload_serialization(self) -> None:
1197+
with self.assertRaises(SerializationError):
1198+
SimpleEnvelope.from_signed("foo") # type: ignore
1199+
1200+
def test_fail_payload_deserialization(self) -> None:
1201+
payloads = [b"[", b'{"_type": "foo"}']
1202+
for payload in payloads:
1203+
envelope = SimpleEnvelope(payload, "bar", [])
1204+
with self.assertRaises(DeserializationError):
1205+
envelope.get_signed()
1206+
1207+
def test_verify_delegate(self) -> None:
1208+
"""Basic verification test.
1209+
1210+
1. Load test metadata for each role
1211+
2. Wrap non-root payloads in envelope serializing the payload
1212+
3. Sign with correct delegated key
1213+
4. Verify delegate with root
1214+
1215+
"""
1216+
root_path = self.metadata_dir / "root.json"
1217+
root = Metadata[Root].from_file(str(root_path)).signed
1218+
1219+
for role in [Timestamp, Snapshot, Targets]:
1220+
metadata_path = self.metadata_dir / f"{role.type}.json"
1221+
metadata = Metadata.from_file(str(metadata_path))
1222+
self.assertIsInstance(metadata.signed, role)
1223+
1224+
signer = self.signer_store[role.type]
1225+
self.assertIn(
1226+
signer.key_dict["keyid"], root.roles[role.type].keyids
1227+
)
1228+
1229+
envelope = SimpleEnvelope.from_signed(metadata.signed)
1230+
envelope.sign(signer)
1231+
self.assertTrue(len(envelope.signatures) == 1)
1232+
1233+
root.verify_delegate(
1234+
role.type, envelope.pae(), envelope.signatures_dict
1235+
)
1236+
1237+
11471238
# Run unit test.
11481239
if __name__ == "__main__":
11491240
utils.configure_test_logging(sys.argv)

tests/test_trusted_metadata_set.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from tests import utils
1717
from tuf.api import exceptions
18+
from tuf.api.dsse import SimpleEnvelope
1819
from tuf.api.metadata import (
1920
Metadata,
2021
MetaFile,
@@ -25,7 +26,10 @@
2526
Timestamp,
2627
)
2728
from tuf.api.serialization.json import JSONSerializer
28-
from tuf.ngclient._internal.trusted_metadata_set import TrustedMetadataSet
29+
from tuf.ngclient._internal.trusted_metadata_set import (
30+
TrustedMetadataSet,
31+
_load_from_simple_envelope,
32+
)
2933
from tuf.ngclient.config import EnvelopeType
3034

3135
logger = logging.getLogger(__name__)
@@ -490,6 +494,52 @@ def target_expired_modifier(target: Targets) -> None:
490494

491495
# TODO test updating over initial metadata (new keys, newer timestamp, etc)
492496

497+
def test_load_from_simple_envelope(self) -> None:
498+
"""Basic unit test for ``_load_from_simple_envelope`` helper.
499+
500+
TODO: Test via trusted metadata set tests like for traditional metadata
501+
"""
502+
metadata = Metadata.from_bytes(self.metadata[Root.type])
503+
root = metadata.signed
504+
envelope = SimpleEnvelope.from_signed(root)
505+
506+
# Unwrap unsigned envelope without verification
507+
envelope_bytes = envelope.to_bytes()
508+
payload_obj, signed_bytes, signatures = _load_from_simple_envelope(
509+
Root, envelope_bytes
510+
)
511+
512+
self.assertEqual(payload_obj, root)
513+
self.assertEqual(signed_bytes, envelope.pae())
514+
self.assertDictEqual(signatures, {})
515+
516+
# Unwrap correctly signed envelope (use default role name)
517+
sig = envelope.sign(self.keystore[Root.type])
518+
envelope_bytes = envelope.to_bytes()
519+
_, _, signatures = _load_from_simple_envelope(
520+
Root, envelope_bytes, root
521+
)
522+
self.assertDictEqual(signatures, {sig.keyid: sig})
523+
524+
# Load correctly signed envelope (with explicit role name)
525+
_, _, signatures = _load_from_simple_envelope(
526+
Root, envelope.to_bytes(), root, Root.type
527+
)
528+
self.assertDictEqual(signatures, {sig.keyid: sig})
529+
530+
# Fail load envelope with unexpected 'payload_type'
531+
envelope_bad_type = SimpleEnvelope.from_signed(root)
532+
envelope_bad_type.payload_type = "foo"
533+
envelope_bad_type_bytes = envelope_bad_type.to_bytes()
534+
with self.assertRaises(exceptions.RepositoryError):
535+
_load_from_simple_envelope(Root, envelope_bad_type_bytes)
536+
537+
# Fail load envelope with unexpected payload type
538+
envelope_bad_signed = SimpleEnvelope.from_signed(root)
539+
envelope_bad_signed_bytes = envelope_bad_signed.to_bytes()
540+
with self.assertRaises(exceptions.RepositoryError):
541+
_load_from_simple_envelope(Targets, envelope_bad_signed_bytes)
542+
493543

494544
if __name__ == "__main__":
495545
utils.configure_test_logging(sys.argv)

0 commit comments

Comments
 (0)