From cf34b788e0f0b2ccc1abc626395f460002894971 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Fri, 13 Dec 2024 12:31:27 +0200 Subject: [PATCH] Remove sct from FulcioCertificateSigningResponse Simplify FulcioCertificateSigningResponse by removing sct field from it. This changes the (internal) fulcio module API. The only place that needs the SCT is verify_sct() and it already gets the certificate which it can trivially get the SCT from. This makes get_signed_certificate_timestamp() an internal implementation detail of verify_sct() which is nice. FulcioSigningCert.post() changes in that it could now return a response without an SCT: this is ok as it is immediately verified in the callsite in Signer._signing_cert(). Signed-off-by: Jussi Kukkonen --- sigstore/_internal/fulcio/client.py | 10 +--------- sigstore/_internal/sct.py | 16 +++++++++------- sigstore/sign.py | 12 +++--------- sigstore/verify/verifier.py | 4 +--- 4 files changed, 14 insertions(+), 28 deletions(-) diff --git a/sigstore/_internal/fulcio/client.py b/sigstore/_internal/fulcio/client.py index ea7d9752c..5fe6f0674 100644 --- a/sigstore/_internal/fulcio/client.py +++ b/sigstore/_internal/fulcio/client.py @@ -33,10 +33,8 @@ CertificateSigningRequest, load_pem_x509_certificate, ) -from cryptography.x509.certificate_transparency import SignedCertificateTimestamp from sigstore._internal import USER_AGENT -from sigstore._internal.sct import get_signed_certificate_timestamp from sigstore._utils import B64Str from sigstore.oidc import IdentityToken @@ -58,7 +56,6 @@ class FulcioCertificateSigningResponse: cert: Certificate chain: List[Certificate] - sct: SignedCertificateTimestamp @dataclass(frozen=True) @@ -137,12 +134,7 @@ def post( cert = load_pem_x509_certificate(certificates[0].encode()) chain = [load_pem_x509_certificate(c.encode()) for c in certificates[1:]] - try: - sct = get_signed_certificate_timestamp(cert) - except ValueError as ex: - raise FulcioClientError(ex) - - return FulcioCertificateSigningResponse(cert, chain, sct) + return FulcioCertificateSigningResponse(cert, chain) class FulcioTrustBundle(_Endpoint): diff --git a/sigstore/_internal/sct.py b/sigstore/_internal/sct.py index c146de6c9..f9b6fe2cd 100644 --- a/sigstore/_internal/sct.py +++ b/sigstore/_internal/sct.py @@ -148,27 +148,28 @@ def _get_issuer_cert(chain: List[Certificate]) -> Certificate: return issuer -def get_signed_certificate_timestamp( +def _get_signed_certificate_timestamp( certificate: Certificate, ) -> SignedCertificateTimestamp: """Retrieve the embedded SCT from the certificate. - Raise ValueError if certificate does not contain exactly one SCT + Raise VerificationError if certificate does not contain exactly one SCT """ try: timestamps = certificate.extensions.get_extension_for_class( PrecertificateSignedCertificateTimestamps ).value except ExtensionNotFound: - raise ValueError( + raise VerificationError( "Certificate does not contain a signed certificate timestamp extension" ) if len(timestamps) != 1: - raise ValueError( - f"Expected one certificate timestamp, found {len(timestamps)}." + raise VerificationError( + f"Expected one certificate timestamp, found {len(timestamps)}" ) - return timestamps[0] + sct: SignedCertificateTimestamp = timestamps[0] + return sct def _cert_is_ca(cert: Certificate) -> bool: @@ -182,7 +183,6 @@ def _cert_is_ca(cert: Certificate) -> bool: def verify_sct( - sct: SignedCertificateTimestamp, cert: Certificate, chain: List[Certificate], ct_keyring: CTKeyring, @@ -196,6 +196,8 @@ def verify_sct( log to sign SCTs). """ + sct = _get_signed_certificate_timestamp(cert) + issuer_key_id = None if sct.entry_type == LogEntryType.PRE_CERTIFICATE: # If we're verifying an SCT for a precertificate, we need to diff --git a/sigstore/sign.py b/sigstore/sign.py index 6afc7d74c..a87dcdb6e 100644 --- a/sigstore/sign.py +++ b/sigstore/sign.py @@ -161,21 +161,15 @@ def _signing_cert( certificate_request, self._identity_token ) - # Verify the SCT - sct = certificate_response.sct - cert = certificate_response.cert - chain = certificate_response.chain - verify_sct( - sct, - cert, - chain, + certificate_response.cert, + certificate_response.chain, self._signing_ctx._trusted_root.ct_keyring(KeyringPurpose.SIGN), ) _logger.debug("Successfully verified SCT...") - return cert + return certificate_response.cert def _finalize_sign( self, diff --git a/sigstore/verify/verifier.py b/sigstore/verify/verifier.py index bec76b647..000e618b8 100644 --- a/sigstore/verify/verifier.py +++ b/sigstore/verify/verifier.py @@ -43,7 +43,6 @@ from sigstore._internal.rekor import _hashedrekord_from_parts from sigstore._internal.rekor.client import RekorClient from sigstore._internal.sct import ( - get_signed_certificate_timestamp, verify_sct, ) from sigstore._internal.timestamp import TimestampSource, TimestampVerificationResult @@ -341,12 +340,11 @@ def _verify_common_signing_cert( # (2): verify the signing certificate's SCT. try: verify_sct( - get_signed_certificate_timestamp(cert), cert, [parent_cert.to_cryptography() for parent_cert in chain], self._trusted_root.ct_keyring(KeyringPurpose.VERIFY), ) - except (ValueError, VerificationError) as e: + except VerificationError as e: raise VerificationError(f"failed to verify SCT on signing certificate: {e}") # (3): verify the signing certificate against the Sigstore