From dcd178a24341101a543a6e564ef78364847a0bfe Mon Sep 17 00:00:00 2001 From: giulio <66009328+lsd-cat@users.noreply.github.com> Date: Mon, 29 Jun 2026 01:08:59 +0200 Subject: [PATCH] =?UTF-8?q?sigstore:=20reject=20legacy=20x509CertificateCh?= =?UTF-8?q?ain=20bundle=20format=20(SPEC=20=C2=A75.2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sigstore-python parses the legacy v0.1/v0.2 bundle layout (signing cert under verificationMaterial.x509CertificateChain). Per SPEC §5.2 the legacy layout MUST be rejected: it can carry intermediate/root CA certs (a misuse vector the v0.3 single-certificate form avoids), and tinfoil only produces v0.3 bundles. reject_legacy_bundle_format rejects a bundle whose verificationMaterial uses x509CertificateChain; called ahead of Bundle.from_json in the production verifier. Matches tinfoil-go/-rs/-js. Stacked on fix/sigstore-duplicate-sct-log. Co-Authored-By: Claude Opus 4.8 --- src/tinfoil/sigstore.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/tinfoil/sigstore.py b/src/tinfoil/sigstore.py index bc33fd8..9b65400 100644 --- a/src/tinfoil/sigstore.py +++ b/src/tinfoil/sigstore.py @@ -13,6 +13,27 @@ OIDC_ISSUER = "https://token.actions.githubusercontent.com" +def reject_legacy_bundle_format(bundle_json: bytes) -> None: + """SPEC §5.2: only the v0.3 single-certificate bundle layout is accepted. + + The legacy v0.1/v0.2 layout conveys the signing certificate under + verificationMaterial.x509CertificateChain, which may also carry intermediate + or root CA certificates — a misuse vector the v0.3 single-certificate form + avoids. sigstore-python parses the legacy layout, so we reject it explicitly, + matching tinfoil-go / -rs. + """ + try: + b = json.loads(bundle_json) + except (ValueError, TypeError): + return + vm = b.get("verificationMaterial") if isinstance(b, dict) else None + if isinstance(vm, dict) and "x509CertificateChain" in vm: + raise VerificationError( + "legacy bundle format not supported: the x509CertificateChain " + "layout requires the v0.3 single-certificate form" + ) + + def reject_duplicate_sct_logs(bundle: Bundle) -> None: """SPEC §5.2 anti-replay guard: reject a leaf certificate whose embedded SCT list contains two or more SCTs that share the same CT log ID, so a @@ -110,6 +131,10 @@ def _verify_dsse_bundle(bundle_json: bytes, digest: str, repo: str) -> dict: ValueError: If any verification step fails """ verifier = Verifier.production() + + # SPEC §5.2: reject the legacy x509CertificateChain bundle layout. + reject_legacy_bundle_format(bundle_json) + bundle = Bundle.from_json(bundle_json) # SPEC §5.2: reject duplicate-log SCTs before signature/SCT verification.