Skip to content

Commit

Permalink
Remove sct from FulcioCertificateSigningResponse
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
jku committed Dec 13, 2024
1 parent d754b3c commit 97c854f
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 27 deletions.
10 changes: 1 addition & 9 deletions sigstore/_internal/fulcio/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -58,7 +56,6 @@ class FulcioCertificateSigningResponse:

cert: Certificate
chain: List[Certificate]
sct: SignedCertificateTimestamp


@dataclass(frozen=True)
Expand Down Expand Up @@ -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):
Expand Down
14 changes: 8 additions & 6 deletions sigstore/_internal/sct.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
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:
Expand All @@ -182,7 +183,6 @@ def _cert_is_ca(cert: Certificate) -> bool:


def verify_sct(
sct: SignedCertificateTimestamp,
cert: Certificate,
chain: List[Certificate],
ct_keyring: CTKeyring,
Expand All @@ -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
Expand Down
12 changes: 3 additions & 9 deletions sigstore/sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 1 addition & 3 deletions sigstore/verify/verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 97c854f

Please sign in to comment.