Skip to content

Commit 8999094

Browse files
committed
sigstore: refactor purpose handling
Signed-off-by: William Woodruff <william@trailofbits.com>
1 parent 34c7f4b commit 8999094

File tree

3 files changed

+36
-33
lines changed

3 files changed

+36
-33
lines changed

sigstore/_internal/trust.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -217,71 +217,69 @@ def __str__(self) -> str:
217217
return self.value
218218

219219

220-
class TrustedRoot(_TrustedRoot):
221-
"""Complete set of trusted entities for a Sigstore client"""
220+
class TrustedRoot:
221+
"""
222+
The cryptographic root(s) of trust for a Sigstore instance.
223+
"""
222224

223-
purpose: KeyringPurpose
225+
def __init__(self, inner: _TrustedRoot):
226+
self._inner = inner
224227

225228
@classmethod
226229
def from_file(
227230
cls,
228231
path: str,
229-
purpose: KeyringPurpose = KeyringPurpose.VERIFY,
230232
) -> TrustedRoot:
231233
"""Create a new trust root from file"""
232-
trusted_root: TrustedRoot = cls().from_json(Path(path).read_bytes())
233-
trusted_root.purpose = purpose
234-
return trusted_root
234+
inner = _TrustedRoot().from_json(Path(path).read_bytes())
235+
return cls(inner)
235236

236237
@classmethod
237238
def from_tuf(
238239
cls,
239240
url: str,
240241
offline: bool = False,
241-
purpose: KeyringPurpose = KeyringPurpose.VERIFY,
242242
) -> TrustedRoot:
243243
"""Create a new trust root from a TUF repository.
244244
245245
If `offline`, will use trust root in local TUF cache. Otherwise will
246246
update the trust root from remote TUF repository.
247247
"""
248248
path = TrustUpdater(url, offline).get_trusted_root_path()
249-
return cls.from_file(path, purpose)
249+
return cls.from_file(path)
250250

251251
@classmethod
252252
def production(
253253
cls,
254254
offline: bool = False,
255-
purpose: KeyringPurpose = KeyringPurpose.VERIFY,
256255
) -> TrustedRoot:
257256
"""Create new trust root from Sigstore production TUF repository.
258257
259258
If `offline`, will use trust root in local TUF cache. Otherwise will
260259
update the trust root from remote TUF repository.
261260
"""
262-
return cls.from_tuf(DEFAULT_TUF_URL, offline, purpose)
261+
return cls.from_tuf(DEFAULT_TUF_URL, offline)
263262

264263
@classmethod
265264
def staging(
266265
cls,
267266
offline: bool = False,
268-
purpose: KeyringPurpose = KeyringPurpose.VERIFY,
269267
) -> TrustedRoot:
270268
"""Create new trust root from Sigstore staging TUF repository.
271269
272270
If `offline`, will use trust root in local TUF cache. Otherwise will
273271
update the trust root from remote TUF repository.
274272
"""
275-
return cls.from_tuf(STAGING_TUF_URL, offline, purpose)
273+
return cls.from_tuf(STAGING_TUF_URL, offline)
276274

277275
def _get_tlog_keys(
278-
self, tlogs: list[TransparencyLogInstance]
276+
self, tlogs: list[TransparencyLogInstance], purpose: KeyringPurpose
279277
) -> Iterable[_PublicKey]:
280278
"""
281279
Yields an iterator of public keys for transparency log instances that
282280
are suitable for `purpose`.
283281
"""
284-
allow_expired = self.purpose is KeyringPurpose.VERIFY
282+
allow_expired = purpose is KeyringPurpose.VERIFY
285283
for tlog in tlogs:
286284
if not _is_timerange_valid(
287285
tlog.public_key.valid_for, allow_expired=allow_expired
@@ -302,17 +300,17 @@ def _get_ca_keys(
302300
for cert in ca.cert_chain.certificates:
303301
yield cert.raw_bytes
304302

305-
def rekor_keyring(self) -> RekorKeyring:
303+
def rekor_keyring(self, purpose: KeyringPurpose) -> RekorKeyring:
306304
"""Return keyring with keys for Rekor."""
307305

308-
keys: list[_PublicKey] = list(self._get_tlog_keys(self.tlogs))
306+
keys: list[_PublicKey] = list(self._get_tlog_keys(self._inner.tlogs, purpose))
309307
if len(keys) != 1:
310308
raise MetadataError("Did not find one Rekor key in trusted root")
311309
return RekorKeyring(Keyring(keys))
312310

313-
def ct_keyring(self) -> CTKeyring:
311+
def ct_keyring(self, purpose: KeyringPurpose) -> CTKeyring:
314312
"""Return keyring with key for CTFE."""
315-
ctfes: list[_PublicKey] = list(self._get_tlog_keys(self.ctlogs))
313+
ctfes: list[_PublicKey] = list(self._get_tlog_keys(self._inner.ctlogs, purpose))
316314
if not ctfes:
317315
raise MetadataError("CTFE keys not found in trusted root")
318316
return CTKeyring(Keyring(ctfes))
@@ -326,7 +324,9 @@ def get_fulcio_certs(self) -> list[Certificate]:
326324
# been active when the certificate was used to sign.
327325
certs = [
328326
load_der_x509_certificate(c)
329-
for c in self._get_ca_keys(self.certificate_authorities, allow_expired=True)
327+
for c in self._get_ca_keys(
328+
self._inner.certificate_authorities, allow_expired=True
329+
)
330330
]
331331
if not certs:
332332
raise MetadataError("Fulcio certificates not found in trusted root")

sigstore/sign.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,12 @@ def _signing_cert(
165165
cert = certificate_response.cert
166166
chain = certificate_response.chain
167167

168-
verify_sct(sct, cert, chain, self._signing_ctx._trusted_root.ct_keyring())
168+
verify_sct(
169+
sct,
170+
cert,
171+
chain,
172+
self._signing_ctx._trusted_root.ct_keyring(KeyringPurpose.SIGN),
173+
)
169174

170175
_logger.debug("Successfully verified SCT...")
171176

@@ -311,21 +316,21 @@ def production(cls) -> SigningContext:
311316
"""
312317
Return a `SigningContext` instance configured against Sigstore's production-level services.
313318
"""
314-
trusted_root = TrustedRoot.production(purpose=KeyringPurpose.SIGN)
315-
rekor = RekorClient.production()
316319
return cls(
317-
fulcio=FulcioClient.production(), rekor=rekor, trusted_root=trusted_root
320+
fulcio=FulcioClient.production(),
321+
rekor=RekorClient.production(),
322+
trusted_root=TrustedRoot.production(),
318323
)
319324

320325
@classmethod
321326
def staging(cls) -> SigningContext:
322327
"""
323328
Return a `SignerContext` instance configured against Sigstore's staging-level services.
324329
"""
325-
trusted_root = TrustedRoot.staging(purpose=KeyringPurpose.SIGN)
326-
rekor = RekorClient.staging()
327330
return cls(
328-
fulcio=FulcioClient.staging(), rekor=rekor, trusted_root=trusted_root
331+
fulcio=FulcioClient.staging(),
332+
rekor=RekorClient.staging(),
333+
trusted_root=TrustedRoot.staging(),
329334
)
330335

331336
@contextmanager

sigstore/verify/verifier.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,19 @@ def production(cls) -> Verifier:
8181
"""
8282
Return a `Verifier` instance configured against Sigstore's production-level services.
8383
"""
84-
trusted_root = TrustedRoot.production(purpose=KeyringPurpose.VERIFY)
8584
return cls(
8685
rekor=RekorClient.production(),
87-
trusted_root=trusted_root,
86+
trusted_root=TrustedRoot.production(),
8887
)
8988

9089
@classmethod
9190
def staging(cls) -> Verifier:
9291
"""
9392
Return a `Verifier` instance configured against Sigstore's staging-level services.
9493
"""
95-
trusted_root = TrustedRoot.staging(purpose=KeyringPurpose.VERIFY)
9694
return cls(
9795
rekor=RekorClient.staging(),
98-
trusted_root=trusted_root,
96+
trusted_root=TrustedRoot.staging(),
9997
)
10098

10199
def _verify_common_signing_cert(
@@ -166,7 +164,7 @@ def _verify_common_signing_cert(
166164
sct,
167165
cert,
168166
[parent_cert.to_cryptography() for parent_cert in chain],
169-
self._trusted_root.ct_keyring(),
167+
self._trusted_root.ct_keyring(KeyringPurpose.VERIFY),
170168
)
171169
except VerificationError as e:
172170
raise VerificationError(f"failed to verify SCT on signing certificate: {e}")
@@ -190,7 +188,7 @@ def _verify_common_signing_cert(
190188
# (5): verify the inclusion promise for the log entry, if present.
191189
entry = bundle.log_entry
192190
try:
193-
entry._verify(self._trusted_root.rekor_keyring())
191+
entry._verify(self._trusted_root.rekor_keyring(KeyringPurpose.VERIFY))
194192
except VerificationError as exc:
195193
raise VerificationError(f"invalid log entry: {exc}")
196194

0 commit comments

Comments
 (0)