diff --git a/sigstore/verify/verifier.py b/sigstore/verify/verifier.py index 6f1845b74..336ddb7a4 100644 --- a/sigstore/verify/verifier.py +++ b/sigstore/verify/verifier.py @@ -128,9 +128,18 @@ def _verify_signed_timestamp( for certificate_authority in cert_authorities: certificates = certificate_authority.certificates(allow_expired=True) - builder = VerifierBuilder() - for certificate in certificates: - builder.add_root_certificate(certificate) + # We expect at least a signing cert and a root cert but there may be intermediates + if len(certificates) < 2: + _logger.debug("Unable to verify Timestamp: cert chain is incomplete") + continue + + builder = ( + VerifierBuilder() + .tsa_certificate(certificates[0]) + .add_root_certificate(certificates[-1]) + ) + for certificate in certificates[1:-1]: + builder = builder.add_intermediate_certificate(certificate) verifier = builder.build() try: diff --git a/test/assets/tsa/issue1482-message b/test/assets/tsa/issue1482-message new file mode 100644 index 000000000..0669b4beb Binary files /dev/null and b/test/assets/tsa/issue1482-message differ diff --git a/test/assets/tsa/issue1482-timestamp-with-no-cert b/test/assets/tsa/issue1482-timestamp-with-no-cert new file mode 100644 index 000000000..7e34d5cbe Binary files /dev/null and b/test/assets/tsa/issue1482-timestamp-with-no-cert differ diff --git a/test/unit/verify/test_verifier.py b/test/unit/verify/test_verifier.py index 9381d0745..7d1ebda91 100644 --- a/test/unit/verify/test_verifier.py +++ b/test/unit/verify/test_verifier.py @@ -377,3 +377,18 @@ def test_verifier_not_enough_timestamp( Bundle.from_json(asset("tsa/bundle.txt.sigstore").read_bytes()), null_policy, ) + + def test_verify_signed_timestamp_regression(self, asset): + """ + Ensure we correctly verify a timestamp with no embedded certs. + + This is a regression test for # 1482 + """ + verifier = Verifier.staging(offline=True) + ts = rfc3161_client.decode_timestamp_response( + asset("tsa/issue1482-timestamp-with-no-cert").read_bytes() + ) + res = verifier._verify_signed_timestamp( + ts, asset("tsa/issue1482-message").read_bytes() + ) + assert res is not None