|
19 | 19 | from datetime import datetime, timedelta
|
20 | 20 | from typing import Any, Dict, List, Mapping, Optional
|
21 | 21 |
|
22 |
| -from securesystemslib.keys import verify_signature |
| 22 | +from securesystemslib import keys as sslib_keys |
23 | 23 | from securesystemslib.signer import Signature, Signer
|
24 | 24 | from securesystemslib.storage import FilesystemBackend, StorageBackendInterface
|
25 | 25 | from securesystemslib.util import persist_temp_file
|
@@ -250,59 +250,6 @@ def sign(
|
250 | 250 |
|
251 | 251 | return signature
|
252 | 252 |
|
253 |
| - def verify( |
254 |
| - self, |
255 |
| - key: Mapping[str, Any], |
256 |
| - signed_serializer: Optional[SignedSerializer] = None, |
257 |
| - ) -> bool: |
258 |
| - """Verifies 'signatures' over 'signed' that match the passed key by id. |
259 |
| -
|
260 |
| - Arguments: |
261 |
| - key: A securesystemslib-style public key object. |
262 |
| - signed_serializer: A SignedSerializer subclass instance that |
263 |
| - implements the desired canonicalization format. Per default a |
264 |
| - CanonicalJSONSerializer is used. |
265 |
| -
|
266 |
| - Raises: |
267 |
| - # TODO: Revise exception taxonomy |
268 |
| - tuf.exceptions.Error: None or multiple signatures found for key. |
269 |
| - securesystemslib.exceptions.FormatError: Key argument is malformed. |
270 |
| - tuf.api.serialization.SerializationError: |
271 |
| - 'signed' cannot be serialized. |
272 |
| - securesystemslib.exceptions.CryptoError, \ |
273 |
| - securesystemslib.exceptions.UnsupportedAlgorithmError: |
274 |
| - Signing errors. |
275 |
| -
|
276 |
| - Returns: |
277 |
| - A boolean indicating if the signature is valid for the passed key. |
278 |
| -
|
279 |
| - """ |
280 |
| - signatures_for_keyid = list( |
281 |
| - filter(lambda sig: sig.keyid == key["keyid"], self.signatures) |
282 |
| - ) |
283 |
| - |
284 |
| - if not signatures_for_keyid: |
285 |
| - raise exceptions.Error(f"no signature for key {key['keyid']}.") |
286 |
| - |
287 |
| - if len(signatures_for_keyid) > 1: |
288 |
| - raise exceptions.Error( |
289 |
| - f"{len(signatures_for_keyid)} signatures for key " |
290 |
| - f"{key['keyid']}, not sure which one to verify." |
291 |
| - ) |
292 |
| - |
293 |
| - if signed_serializer is None: |
294 |
| - # Use local scope import to avoid circular import errors |
295 |
| - # pylint: disable=import-outside-toplevel |
296 |
| - from tuf.api.serialization.json import CanonicalJSONSerializer |
297 |
| - |
298 |
| - signed_serializer = CanonicalJSONSerializer() |
299 |
| - |
300 |
| - return verify_signature( |
301 |
| - key, |
302 |
| - signatures_for_keyid[0].to_dict(), |
303 |
| - signed_serializer.serialize(self.signed), |
304 |
| - ) |
305 |
| - |
306 | 253 |
|
307 | 254 | class Signed:
|
308 | 255 | """A base class for the signed part of TUF metadata.
|
@@ -417,7 +364,9 @@ class Key:
|
417 | 364 | """A container class representing the public portion of a Key.
|
418 | 365 |
|
419 | 366 | Attributes:
|
420 |
| - keyid: An identifier string |
| 367 | + keyid: An identifier string that must uniquely identify a key within |
| 368 | + the metadata it is used in. This implementation does not verify |
| 369 | + that keyid is the hash of a specific representation of the key. |
421 | 370 | keytype: A string denoting a public key signature system,
|
422 | 371 | such as "rsa", "ed25519", and "ecdsa-sha2-nistp256".
|
423 | 372 | scheme: A string denoting a corresponding signature scheme. For example:
|
@@ -461,6 +410,59 @@ def to_dict(self) -> Dict[str, Any]:
|
461 | 410 | **self.unrecognized_fields,
|
462 | 411 | }
|
463 | 412 |
|
| 413 | + def to_securesystemslib_key(self) -> Dict[str, Any]: |
| 414 | + """Returns a Securesystemslib compatible representation of self.""" |
| 415 | + return { |
| 416 | + "keyid": self.keyid, |
| 417 | + "keytype": self.keytype, |
| 418 | + "scheme": self.scheme, |
| 419 | + "keyval": self.keyval, |
| 420 | + } |
| 421 | + |
| 422 | + def verify_signature( |
| 423 | + self, |
| 424 | + metadata: Metadata, |
| 425 | + signed_serializer: Optional[SignedSerializer] = None, |
| 426 | + ): |
| 427 | + """Verifies that the 'metadata.signatures' contains a signature made |
| 428 | + with this key, correctly signing 'metadata.signed'. |
| 429 | +
|
| 430 | + Arguments: |
| 431 | + metadata: Metadata to verify |
| 432 | + signed_serializer: Optional; SignedSerializer to serialize |
| 433 | + 'metadata.signed' with. Default is CanonicalJSONSerializer. |
| 434 | +
|
| 435 | + Raises: |
| 436 | + UnsignedMetadataError: The signature could not be verified for a |
| 437 | + variety of possible reasons: see error message. |
| 438 | + TODO: Various other errors currently bleed through from lower |
| 439 | + level components: Issue #1351 |
| 440 | + """ |
| 441 | + try: |
| 442 | + sigs = metadata.signatures |
| 443 | + signature = next(sig for sig in sigs if sig.keyid == self.keyid) |
| 444 | + except StopIteration: |
| 445 | + raise exceptions.UnsignedMetadataError( |
| 446 | + f"no signature for key {self.keyid} found in metadata", |
| 447 | + metadata.signed, |
| 448 | + ) from None |
| 449 | + |
| 450 | + if signed_serializer is None: |
| 451 | + # pylint: disable=import-outside-toplevel |
| 452 | + from tuf.api.serialization.json import CanonicalJSONSerializer |
| 453 | + |
| 454 | + signed_serializer = CanonicalJSONSerializer() |
| 455 | + |
| 456 | + if not sslib_keys.verify_signature( |
| 457 | + self.to_securesystemslib_key(), |
| 458 | + signature.to_dict(), |
| 459 | + signed_serializer.serialize(metadata.signed), |
| 460 | + ): |
| 461 | + raise exceptions.UnsignedMetadataError( |
| 462 | + f"Failed to verify {self.keyid} signature for metadata", |
| 463 | + metadata.signed, |
| 464 | + ) |
| 465 | + |
464 | 466 |
|
465 | 467 | class Role:
|
466 | 468 | """A container class containing the set of keyids and threshold associated
|
|
0 commit comments