diff --git a/sigstore/_internal/fulcio/client.py b/sigstore/_internal/fulcio/client.py index 062519186..ea7d9752c 100644 --- a/sigstore/_internal/fulcio/client.py +++ b/sigstore/_internal/fulcio/client.py @@ -36,10 +36,7 @@ from cryptography.x509.certificate_transparency import SignedCertificateTimestamp from sigstore._internal import USER_AGENT -from sigstore._internal.sct import ( - UnexpectedSctCountException, - _get_precertificate_signed_certificate_timestamps, -) +from sigstore._internal.sct import get_signed_certificate_timestamp from sigstore._utils import B64Str from sigstore.oidc import IdentityToken @@ -51,14 +48,6 @@ TRUST_BUNDLE_ENDPOINT = "/api/v2/trustBundle" -class FulcioSCTError(Exception): - """ - Raised on errors when constructing a `FulcioSignedCertificateTimestamp`. - """ - - pass - - class ExpiredCertificate(Exception): """An error raised when the Certificate is expired.""" @@ -149,10 +138,8 @@ def post( chain = [load_pem_x509_certificate(c.encode()) for c in certificates[1:]] try: - # The SignedCertificateTimestamp should be accessed by the index 0 - sct = _get_precertificate_signed_certificate_timestamps(cert)[0] - - except UnexpectedSctCountException as ex: + sct = get_signed_certificate_timestamp(cert) + except ValueError as ex: raise FulcioClientError(ex) return FulcioCertificateSigningResponse(cert, chain, sct) diff --git a/sigstore/_internal/sct.py b/sigstore/_internal/sct.py index 8fd6cc5b2..c146de6c9 100644 --- a/sigstore/_internal/sct.py +++ b/sigstore/_internal/sct.py @@ -148,32 +148,27 @@ def _get_issuer_cert(chain: List[Certificate]) -> Certificate: return issuer -class UnexpectedSctCountException(Exception): - """ - Number of percerts scts is wrong - """ - - pass - - -def _get_precertificate_signed_certificate_timestamps( +def get_signed_certificate_timestamp( certificate: Certificate, -) -> PrecertificateSignedCertificateTimestamps: - # Try to retrieve the embedded SCTs within the cert. +) -> SignedCertificateTimestamp: + """Retrieve the embedded SCT from the certificate. + + Raise ValueError if certificate does not contain exactly one SCT + """ try: - precert_scts_extension = certificate.extensions.get_extension_for_class( + timestamps = certificate.extensions.get_extension_for_class( PrecertificateSignedCertificateTimestamps ).value except ExtensionNotFound: raise ValueError( - "No PrecertificateSignedCertificateTimestamps found for the certificate" + "Certificate does not contain a signed certificate timestamp extension" ) - if len(precert_scts_extension) != 1: - raise UnexpectedSctCountException( - f"Unexpected embedded SCT count in response: {len(precert_scts_extension)} != 1" + if len(timestamps) != 1: + raise ValueError( + f"Expected one certificate timestamp, found {len(timestamps)}." ) - return precert_scts_extension + return timestamps[0] def _cert_is_ca(cert: Certificate) -> bool: diff --git a/sigstore/verify/verifier.py b/sigstore/verify/verifier.py index 59437caf1..bec76b647 100644 --- a/sigstore/verify/verifier.py +++ b/sigstore/verify/verifier.py @@ -43,7 +43,7 @@ from sigstore._internal.rekor import _hashedrekord_from_parts from sigstore._internal.rekor.client import RekorClient from sigstore._internal.sct import ( - _get_precertificate_signed_certificate_timestamps, + get_signed_certificate_timestamp, verify_sct, ) from sigstore._internal.timestamp import TimestampSource, TimestampVerificationResult @@ -339,15 +339,14 @@ def _verify_common_signing_cert( chain = self._verify_chain_at_time(cert_ossl, vts) # (2): verify the signing certificate's SCT. - sct = _get_precertificate_signed_certificate_timestamps(cert)[0] try: verify_sct( - sct, + get_signed_certificate_timestamp(cert), cert, [parent_cert.to_cryptography() for parent_cert in chain], self._trusted_root.ct_keyring(KeyringPurpose.VERIFY), ) - except VerificationError as e: + except (ValueError, VerificationError) as e: raise VerificationError(f"failed to verify SCT on signing certificate: {e}") # (3): verify the signing certificate against the Sigstore