diff --git a/CHANGELOG.md b/CHANGELOG.md index 16db852af..17d2d00d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ All versions prior to 0.9.0 are untracked. ## [Unreleased] +### Fixed + +* verification now ensures that artifact digest documented in bundle and the real digest match + (this is a bundle consistency check: bundle signature was always verified over real digest) + ([#1652](https://github.com/sigstore/sigstore-python/pull/1652)) + ### Removed * Removed support for Python 3.9 as it is end-of-life diff --git a/sigstore/verify/verifier.py b/sigstore/verify/verifier.py index 956a1508b..7b81e9c2b 100644 --- a/sigstore/verify/verifier.py +++ b/sigstore/verify/verifier.py @@ -470,13 +470,24 @@ def verify_artifact( self._verify_common_signing_cert(bundle, policy) hashed_input = sha256_digest(input_) + bundle_signature = bundle._inner.message_signature + if bundle_signature is None: + raise VerificationError("Missing bundle message signature") + + # signature is verified over input digest, but if the bundle documents the digest we still + # want to ensure it matches the input digest: + if ( + bundle_signature.message_digest is not None + and hashed_input.digest != bundle_signature.message_digest.digest + ): + raise VerificationError("Bundle message digest mismatch") # (7): verify that the signature was signed by the public key in the signing certificate. try: signing_key = bundle.signing_certificate.public_key() signing_key = cast(ec.EllipticCurvePublicKey, signing_key) signing_key.verify( - bundle._inner.message_signature.signature, # type: ignore[union-attr] + bundle_signature.signature, hashed_input.digest, ec.ECDSA(hashed_input._as_prehashed()), ) diff --git a/test/unit/verify/test_verifier.py b/test/unit/verify/test_verifier.py index f03de96b6..1a500ec93 100644 --- a/test/unit/verify/test_verifier.py +++ b/test/unit/verify/test_verifier.py @@ -64,6 +64,20 @@ def test_verifier_inconsistent_log_entry(signing_bundle, null_policy): verifier.verify_artifact(file.read_bytes(), bundle, null_policy) +@pytest.mark.staging +def test_verifier_digest_mismatch(signing_bundle, null_policy): + """The signature is over correct content, but digest documented in bundle is wrong""" + (file, bundle) = signing_bundle("bundle.txt") + bundle._inner.message_signature.message_digest.digest = b"" + + verifier = Verifier.staging() + with pytest.raises( + VerificationError, + match="digest mismatch", + ): + verifier.verify_artifact(file.read_bytes(), bundle, null_policy) + + @pytest.mark.staging def test_verifier_multiple_verifications(signing_materials, null_policy): verifier = Verifier.staging()