Skip to content

Commit 8b4b3fe

Browse files
jkuwoodruffw
andauthored
Minor refactoring of Fulcio SCT handling (#1259)
Co-authored-by: William Woodruff <william@trailofbits.com>
1 parent 52846d9 commit 8b4b3fe

File tree

4 files changed

+20
-53
lines changed

4 files changed

+20
-53
lines changed

sigstore/_internal/fulcio/client.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,8 @@
3333
CertificateSigningRequest,
3434
load_pem_x509_certificate,
3535
)
36-
from cryptography.x509.certificate_transparency import SignedCertificateTimestamp
3736

3837
from sigstore._internal import USER_AGENT
39-
from sigstore._internal.sct import (
40-
UnexpectedSctCountException,
41-
_get_precertificate_signed_certificate_timestamps,
42-
)
4338
from sigstore._utils import B64Str
4439
from sigstore.oidc import IdentityToken
4540

@@ -51,14 +46,6 @@
5146
TRUST_BUNDLE_ENDPOINT = "/api/v2/trustBundle"
5247

5348

54-
class FulcioSCTError(Exception):
55-
"""
56-
Raised on errors when constructing a `FulcioSignedCertificateTimestamp`.
57-
"""
58-
59-
pass
60-
61-
6249
class ExpiredCertificate(Exception):
6350
"""An error raised when the Certificate is expired."""
6451

@@ -69,7 +56,6 @@ class FulcioCertificateSigningResponse:
6956

7057
cert: Certificate
7158
chain: List[Certificate]
72-
sct: SignedCertificateTimestamp
7359

7460

7561
@dataclass(frozen=True)
@@ -148,14 +134,7 @@ def post(
148134
cert = load_pem_x509_certificate(certificates[0].encode())
149135
chain = [load_pem_x509_certificate(c.encode()) for c in certificates[1:]]
150136

151-
try:
152-
# The SignedCertificateTimestamp should be accessed by the index 0
153-
sct = _get_precertificate_signed_certificate_timestamps(cert)[0]
154-
155-
except UnexpectedSctCountException as ex:
156-
raise FulcioClientError(ex)
157-
158-
return FulcioCertificateSigningResponse(cert, chain, sct)
137+
return FulcioCertificateSigningResponse(cert, chain)
159138

160139

161140
class FulcioTrustBundle(_Endpoint):

sigstore/_internal/sct.py

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -148,32 +148,28 @@ def _get_issuer_cert(chain: List[Certificate]) -> Certificate:
148148
return issuer
149149

150150

151-
class UnexpectedSctCountException(Exception):
152-
"""
153-
Number of percerts scts is wrong
154-
"""
155-
156-
pass
157-
158-
159-
def _get_precertificate_signed_certificate_timestamps(
151+
def _get_signed_certificate_timestamp(
160152
certificate: Certificate,
161-
) -> PrecertificateSignedCertificateTimestamps:
162-
# Try to retrieve the embedded SCTs within the cert.
153+
) -> SignedCertificateTimestamp:
154+
"""Retrieve the embedded SCT from the certificate.
155+
156+
Raise VerificationError if certificate does not contain exactly one SCT
157+
"""
163158
try:
164-
precert_scts_extension = certificate.extensions.get_extension_for_class(
159+
timestamps = certificate.extensions.get_extension_for_class(
165160
PrecertificateSignedCertificateTimestamps
166161
).value
167162
except ExtensionNotFound:
168-
raise ValueError(
169-
"No PrecertificateSignedCertificateTimestamps found for the certificate"
163+
raise VerificationError(
164+
"Certificate does not contain a signed certificate timestamp extension"
170165
)
171166

172-
if len(precert_scts_extension) != 1:
173-
raise UnexpectedSctCountException(
174-
f"Unexpected embedded SCT count in response: {len(precert_scts_extension)} != 1"
167+
if len(timestamps) != 1:
168+
raise VerificationError(
169+
f"Expected one certificate timestamp, found {len(timestamps)}"
175170
)
176-
return precert_scts_extension
171+
sct: SignedCertificateTimestamp = timestamps[0]
172+
return sct
177173

178174

179175
def _cert_is_ca(cert: Certificate) -> bool:
@@ -187,7 +183,6 @@ def _cert_is_ca(cert: Certificate) -> bool:
187183

188184

189185
def verify_sct(
190-
sct: SignedCertificateTimestamp,
191186
cert: Certificate,
192187
chain: List[Certificate],
193188
ct_keyring: CTKeyring,
@@ -201,6 +196,8 @@ def verify_sct(
201196
log to sign SCTs).
202197
"""
203198

199+
sct = _get_signed_certificate_timestamp(cert)
200+
204201
issuer_key_id = None
205202
if sct.entry_type == LogEntryType.PRE_CERTIFICATE:
206203
# If we're verifying an SCT for a precertificate, we need to

sigstore/sign.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,21 +161,15 @@ def _signing_cert(
161161
certificate_request, self._identity_token
162162
)
163163

164-
# Verify the SCT
165-
sct = certificate_response.sct
166-
cert = certificate_response.cert
167-
chain = certificate_response.chain
168-
169164
verify_sct(
170-
sct,
171-
cert,
172-
chain,
165+
certificate_response.cert,
166+
certificate_response.chain,
173167
self._signing_ctx._trusted_root.ct_keyring(KeyringPurpose.SIGN),
174168
)
175169

176170
_logger.debug("Successfully verified SCT...")
177171

178-
return cert
172+
return certificate_response.cert
179173

180174
def _finalize_sign(
181175
self,

sigstore/verify/verifier.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
from sigstore._internal.rekor import _hashedrekord_from_parts
4444
from sigstore._internal.rekor.client import RekorClient
4545
from sigstore._internal.sct import (
46-
_get_precertificate_signed_certificate_timestamps,
4746
verify_sct,
4847
)
4948
from sigstore._internal.timestamp import TimestampSource, TimestampVerificationResult
@@ -339,10 +338,8 @@ def _verify_common_signing_cert(
339338
chain = self._verify_chain_at_time(cert_ossl, vts)
340339

341340
# (2): verify the signing certificate's SCT.
342-
sct = _get_precertificate_signed_certificate_timestamps(cert)[0]
343341
try:
344342
verify_sct(
345-
sct,
346343
cert,
347344
[parent_cert.to_cryptography() for parent_cert in chain],
348345
self._trusted_root.ct_keyring(KeyringPurpose.VERIFY),

0 commit comments

Comments
 (0)