Skip to content

Commit

Permalink
Merge 1ce36d0 into de78251
Browse files Browse the repository at this point in the history
  • Loading branch information
jku committed Jun 9, 2021
2 parents de78251 + 1ce36d0 commit 581960e
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 19 deletions.
12 changes: 9 additions & 3 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def test_sign_verify(self):
metadata_obj = Metadata.from_file(path)

# ... it has a single existing signature,
self.assertTrue(len(metadata_obj.signatures) == 1)
self.assertEqual(len(metadata_obj.signatures), 1)
# ... which is valid for the correct key.
targets_key.verify_signature(metadata_obj)
with self.assertRaises(tuf.exceptions.UnsignedMetadataError):
Expand All @@ -185,7 +185,7 @@ def test_sign_verify(self):
# Append a new signature with the unrelated key and assert that ...
metadata_obj.sign(sslib_signer, append=True)
# ... there are now two signatures, and
self.assertTrue(len(metadata_obj.signatures) == 2)
self.assertEqual(len(metadata_obj.signatures), 2)
# ... both are valid for the corresponding keys.
targets_key.verify_signature(metadata_obj)
snapshot_key.verify_signature(metadata_obj)
Expand All @@ -194,7 +194,7 @@ def test_sign_verify(self):
# Create and assign (don't append) a new signature and assert that ...
metadata_obj.sign(sslib_signer, append=False)
# ... there now is only one signature,
self.assertTrue(len(metadata_obj.signatures) == 1)
self.assertEqual(len(metadata_obj.signatures), 1)
# ... valid for that key.
timestamp_key.verify_signature(metadata_obj)
with self.assertRaises(tuf.exceptions.UnsignedMetadataError):
Expand Down Expand Up @@ -236,6 +236,12 @@ def test_metadata_base(self):
self.assertFalse(is_expired)
md.signed.expires = expires

# Test deserializing metadata with non-unique signatures:
data = md.to_dict()
data["signatures"].append({"keyid": data["signatures"][0]["keyid"], "sig": "foo"})
with self.assertRaises(ValueError):
Metadata.from_dict(data)


def test_metafile_class(self):
# Test from_dict and to_dict with all attributes.
Expand Down
36 changes: 20 additions & 16 deletions tuf/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"""
import abc
import tempfile
from collections import OrderedDict
from datetime import datetime, timedelta
from typing import Any, ClassVar, Dict, List, Mapping, Optional, Tuple, Type

Expand Down Expand Up @@ -48,12 +49,13 @@ class Metadata:
signed: A subclass of Signed, which has the actual metadata payload,
i.e. one of Targets, Snapshot, Timestamp or Root.
signatures: A list of Securesystemslib Signature objects, each signing
the canonical serialized representation of 'signed'.
signatures: An ordered dictionary of keyids to Signature objects, each
signing the canonical serialized representation of 'signed'.
"""

def __init__(self, signed: "Signed", signatures: List[Signature]) -> None:
def __init__(
self, signed: "Signed", signatures: "OrderedDict[str, Signature]"
):
self.signed = signed
self.signatures = signatures

Expand Down Expand Up @@ -89,10 +91,15 @@ def from_dict(cls, metadata: Dict[str, Any]) -> "Metadata":
else:
raise ValueError(f'unrecognized metadata type "{_type}"')

signatures = []
for signature in metadata.pop("signatures"):
signature_obj = Signature.from_dict(signature)
signatures.append(signature_obj)
# Make sure signatures are unique
signatures: "OrderedDict[str, Signature]" = OrderedDict()
for sig_dict in metadata.pop("signatures"):
sig = Signature.from_dict(sig_dict)
if sig.keyid in signatures:
raise ValueError(
f"Multiple signatures found for keyid {sig.keyid}"
)
signatures[sig.keyid] = sig

return cls(
signed=inner_cls.from_dict(metadata.pop("signed")),
Expand Down Expand Up @@ -164,9 +171,7 @@ def from_bytes(
def to_dict(self) -> Dict[str, Any]:
"""Returns the dict representation of self."""

signatures = []
for sig in self.signatures:
signatures.append(sig.to_dict())
signatures = [sig.to_dict() for sig in self.signatures.values()]

return {"signatures": signatures, "signed": self.signed.to_dict()}

Expand Down Expand Up @@ -245,9 +250,9 @@ def sign(
signature = signer.sign(signed_serializer.serialize(self.signed))

if append:
self.signatures.append(signature)
self.signatures[signature.keyid] = signature
else:
self.signatures = [signature]
self.signatures = OrderedDict({signature.keyid: signature})

return signature

Expand Down Expand Up @@ -453,9 +458,8 @@ def verify_signature(
level components: Issue #1351
"""
try:
sigs = metadata.signatures
signature = next(sig for sig in sigs if sig.keyid == self.keyid)
except StopIteration:
signature = metadata.signatures[self.keyid]
except KeyError:
raise exceptions.UnsignedMetadataError(
f"no signature for key {self.keyid} found in metadata",
metadata.signed,
Expand Down

0 comments on commit 581960e

Please sign in to comment.