|
17 | 17 | """
|
18 | 18 | import abc
|
19 | 19 | import tempfile
|
| 20 | +from collections import OrderedDict |
20 | 21 | from datetime import datetime, timedelta
|
21 | 22 | from typing import Any, ClassVar, Dict, List, Mapping, Optional, Tuple, Type
|
22 | 23 |
|
@@ -48,12 +49,13 @@ class Metadata:
|
48 | 49 | signed: A subclass of Signed, which has the actual metadata payload,
|
49 | 50 | i.e. one of Targets, Snapshot, Timestamp or Root.
|
50 | 51 |
|
51 |
| - signatures: A list of Securesystemslib Signature objects, each signing |
52 |
| - the canonical serialized representation of 'signed'. |
53 |
| -
|
| 52 | + signatures: An ordered dictionary of keyids to Signature objects, each |
| 53 | + signing the canonical serialized representation of 'signed'. |
54 | 54 | """
|
55 | 55 |
|
56 |
| - def __init__(self, signed: "Signed", signatures: List[Signature]) -> None: |
| 56 | + def __init__( |
| 57 | + self, signed: "Signed", signatures: "OrderedDict[str, Signature]" |
| 58 | + ): |
57 | 59 | self.signed = signed
|
58 | 60 | self.signatures = signatures
|
59 | 61 |
|
@@ -89,10 +91,15 @@ def from_dict(cls, metadata: Dict[str, Any]) -> "Metadata":
|
89 | 91 | else:
|
90 | 92 | raise ValueError(f'unrecognized metadata type "{_type}"')
|
91 | 93 |
|
92 |
| - signatures = [] |
93 |
| - for signature in metadata.pop("signatures"): |
94 |
| - signature_obj = Signature.from_dict(signature) |
95 |
| - signatures.append(signature_obj) |
| 94 | + # Make sure signatures are unique |
| 95 | + signatures: "OrderedDict[str, Signature]" = OrderedDict() |
| 96 | + for sig_dict in metadata.pop("signatures"): |
| 97 | + sig = Signature.from_dict(sig_dict) |
| 98 | + if sig.keyid in signatures: |
| 99 | + raise ValueError( |
| 100 | + f"Multiple signatures found for keyid {sig.keyid}" |
| 101 | + ) |
| 102 | + signatures[sig.keyid] = sig |
96 | 103 |
|
97 | 104 | return cls(
|
98 | 105 | signed=inner_cls.from_dict(metadata.pop("signed")),
|
@@ -164,9 +171,7 @@ def from_bytes(
|
164 | 171 | def to_dict(self) -> Dict[str, Any]:
|
165 | 172 | """Returns the dict representation of self."""
|
166 | 173 |
|
167 |
| - signatures = [] |
168 |
| - for sig in self.signatures: |
169 |
| - signatures.append(sig.to_dict()) |
| 174 | + signatures = [sig.to_dict() for sig in self.signatures.values()] |
170 | 175 |
|
171 | 176 | return {"signatures": signatures, "signed": self.signed.to_dict()}
|
172 | 177 |
|
@@ -244,10 +249,10 @@ def sign(
|
244 | 249 |
|
245 | 250 | signature = signer.sign(signed_serializer.serialize(self.signed))
|
246 | 251 |
|
247 |
| - if append: |
248 |
| - self.signatures.append(signature) |
249 |
| - else: |
250 |
| - self.signatures = [signature] |
| 252 | + if not append: |
| 253 | + self.signatures.clear() |
| 254 | + |
| 255 | + self.signatures[signature.keyid] = signature |
251 | 256 |
|
252 | 257 | return signature
|
253 | 258 |
|
@@ -453,9 +458,8 @@ def verify_signature(
|
453 | 458 | level components: Issue #1351
|
454 | 459 | """
|
455 | 460 | try:
|
456 |
| - sigs = metadata.signatures |
457 |
| - signature = next(sig for sig in sigs if sig.keyid == self.keyid) |
458 |
| - except StopIteration: |
| 461 | + signature = metadata.signatures[self.keyid] |
| 462 | + except KeyError: |
459 | 463 | raise exceptions.UnsignedMetadataError(
|
460 | 464 | f"no signature for key {self.keyid} found in metadata",
|
461 | 465 | metadata.signed,
|
|
0 commit comments