sigstore.sign
API for signing artifacts.
Example:
from pathlib import Path
from sigstore.sign import SigningContext
from sigstore.oidc import Issuer
issuer = Issuer.production()
identity = issuer.identity_token()
# The artifact to sign
artifact = Path("foo.txt").read_bytes()
signing_ctx = SigningContext.production()
with signing_ctx.signer(identity, cache=True) as signer:
result = signer.sign_artifact(artifact)
print(result)
1# Copyright 2022 The Sigstore Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15""" 16API for signing artifacts. 17 18Example: 19 20```python 21from pathlib import Path 22 23from sigstore.sign import SigningContext 24from sigstore.oidc import Issuer 25 26issuer = Issuer.production() 27identity = issuer.identity_token() 28 29# The artifact to sign 30artifact = Path("foo.txt").read_bytes() 31 32signing_ctx = SigningContext.production() 33with signing_ctx.signer(identity, cache=True) as signer: 34 result = signer.sign_artifact(artifact) 35 print(result) 36``` 37""" 38 39from __future__ import annotations 40 41import base64 42import logging 43from contextlib import contextmanager 44from datetime import datetime, timezone 45from typing import Iterator, Optional 46 47import cryptography.x509 as x509 48import rekor_types 49from cryptography.hazmat.primitives import hashes, serialization 50from cryptography.hazmat.primitives.asymmetric import ec 51from cryptography.x509.oid import NameOID 52from sigstore_protobuf_specs.dev.sigstore.common.v1 import ( 53 HashOutput, 54 MessageSignature, 55) 56 57from sigstore import dsse 58from sigstore import hashes as sigstore_hashes 59from sigstore._internal.fulcio import ( 60 ExpiredCertificate, 61 FulcioClient, 62) 63from sigstore._internal.rekor.client import RekorClient 64from sigstore._internal.sct import verify_sct 65from sigstore._internal.trust import ClientTrustConfig, KeyringPurpose, TrustedRoot 66from sigstore._utils import sha256_digest 67from sigstore.models import Bundle 68from sigstore.oidc import ExpiredIdentity, IdentityToken 69 70_logger = logging.getLogger(__name__) 71 72 73class Signer: 74 """ 75 The primary API for signing operations. 76 """ 77 78 def __init__( 79 self, 80 identity_token: IdentityToken, 81 signing_ctx: SigningContext, 82 cache: bool = True, 83 ) -> None: 84 """ 85 Create a new `Signer`. 86 87 `identity_token` is the identity token used to request a signing certificate 88 from Fulcio. 89 90 `signing_ctx` is a `SigningContext` that keeps information about the signing 91 configuration. 92 93 `cache` determines whether the signing certificate and ephemeral private key 94 should be reused (until the certificate expires) to sign different artifacts. 95 Default is `True`. 96 """ 97 self._identity_token = identity_token 98 self._signing_ctx: SigningContext = signing_ctx 99 self.__cached_private_key: Optional[ec.EllipticCurvePrivateKey] = None 100 self.__cached_signing_certificate: Optional[x509.Certificate] = None 101 if cache: 102 _logger.debug("Generating ephemeral keys...") 103 self.__cached_private_key = ec.generate_private_key(ec.SECP256R1()) 104 _logger.debug("Requesting ephemeral certificate...") 105 self.__cached_signing_certificate = self._signing_cert() 106 107 @property 108 def _private_key(self) -> ec.EllipticCurvePrivateKey: 109 """Get or generate a signing key.""" 110 if self.__cached_private_key is None: 111 _logger.debug("no cached key; generating ephemeral key") 112 return ec.generate_private_key(ec.SECP256R1()) 113 return self.__cached_private_key 114 115 def _signing_cert( 116 self, 117 ) -> x509.Certificate: 118 """ 119 Get or request a signing certificate from Fulcio. 120 121 Internally, this performs a CSR against Fulcio and verifies that 122 the returned certificate is present in Fulcio's CT log. 123 """ 124 125 # Our CSR cannot possibly succeed if our underlying identity token 126 # is expired. 127 if not self._identity_token.in_validity_period(): 128 raise ExpiredIdentity 129 130 # If it exists, verify if the current certificate is expired 131 if self.__cached_signing_certificate: 132 not_valid_after = self.__cached_signing_certificate.not_valid_after_utc 133 if datetime.now(timezone.utc) > not_valid_after: 134 raise ExpiredCertificate 135 return self.__cached_signing_certificate 136 137 else: 138 _logger.debug("Retrieving signed certificate...") 139 140 # Build an X.509 Certificiate Signing Request 141 builder = ( 142 x509.CertificateSigningRequestBuilder() 143 .subject_name( 144 x509.Name( 145 [ 146 x509.NameAttribute( 147 NameOID.EMAIL_ADDRESS, self._identity_token._identity 148 ), 149 ] 150 ) 151 ) 152 .add_extension( 153 x509.BasicConstraints(ca=False, path_length=None), 154 critical=True, 155 ) 156 ) 157 certificate_request = builder.sign(self._private_key, hashes.SHA256()) 158 159 certificate_response = self._signing_ctx._fulcio.signing_cert.post( 160 certificate_request, self._identity_token 161 ) 162 163 # Verify the SCT 164 sct = certificate_response.sct 165 cert = certificate_response.cert 166 chain = certificate_response.chain 167 168 verify_sct( 169 sct, 170 cert, 171 chain, 172 self._signing_ctx._trusted_root.ct_keyring(KeyringPurpose.SIGN), 173 ) 174 175 _logger.debug("Successfully verified SCT...") 176 177 return cert 178 179 def _finalize_sign( 180 self, 181 cert: x509.Certificate, 182 content: MessageSignature | dsse.Envelope, 183 proposed_entry: rekor_types.Hashedrekord | rekor_types.Dsse, 184 ) -> Bundle: 185 """ 186 Perform the common "finalizing" steps in a Sigstore signing flow. 187 """ 188 # Submit the proposed entry to the transparency log 189 entry = self._signing_ctx._rekor.log.entries.post(proposed_entry) 190 191 _logger.debug(f"Transparency log entry created with index: {entry.log_index}") 192 193 return Bundle._from_parts(cert, content, entry) 194 195 def sign_dsse( 196 self, 197 input_: dsse.Statement, 198 ) -> Bundle: 199 """ 200 Sign the given in-toto statement as a DSSE envelope, and return a 201 `Bundle` containing the signed result. 202 203 This API is **only** for in-toto statements; to sign arbitrary artifacts, 204 use `sign_artifact` instead. 205 """ 206 cert = self._signing_cert() 207 208 # Prepare inputs 209 b64_cert = base64.b64encode( 210 cert.public_bytes(encoding=serialization.Encoding.PEM) 211 ) 212 213 # Sign the statement, producing a DSSE envelope 214 content = dsse._sign(self._private_key, input_) 215 216 # Create the proposed DSSE log entry 217 proposed_entry = rekor_types.Dsse( 218 spec=rekor_types.dsse.DsseSchema( 219 # NOTE: mypy can't see that this kwarg is correct due to two interacting 220 # behaviors/bugs (one pydantic, one datamodel-codegen): 221 # See: <https://github.com/pydantic/pydantic/discussions/7418#discussioncomment-9024927> 222 # See: <https://github.com/koxudaxi/datamodel-code-generator/issues/1903> 223 proposed_content=rekor_types.dsse.ProposedContent( # type: ignore[call-arg] 224 envelope=content.to_json(), 225 verifiers=[b64_cert.decode()], 226 ), 227 ), 228 ) 229 230 return self._finalize_sign(cert, content, proposed_entry) 231 232 def sign_artifact( 233 self, 234 input_: bytes | sigstore_hashes.Hashed, 235 ) -> Bundle: 236 """ 237 Sign an artifact, and return a `Bundle` corresponding to the signed result. 238 239 The input can be one of two forms: 240 241 1. A `bytes` buffer; 242 2. A `Hashed` object, containing a pre-hashed input (e.g., for inputs 243 that are too large to buffer into memory). 244 245 Regardless of the input format, the signing operation will produce a 246 `hashedrekord` entry within the bundle. No other entry types 247 are supported by this API. 248 """ 249 250 cert = self._signing_cert() 251 252 # Prepare inputs 253 b64_cert = base64.b64encode( 254 cert.public_bytes(encoding=serialization.Encoding.PEM) 255 ) 256 257 # Sign artifact 258 hashed_input = sha256_digest(input_) 259 260 artifact_signature = self._private_key.sign( 261 hashed_input.digest, ec.ECDSA(hashed_input._as_prehashed()) 262 ) 263 264 content = MessageSignature( 265 message_digest=HashOutput( 266 algorithm=hashed_input.algorithm, 267 digest=hashed_input.digest, 268 ), 269 signature=artifact_signature, 270 ) 271 272 # Create the proposed hashedrekord entry 273 proposed_entry = rekor_types.Hashedrekord( 274 spec=rekor_types.hashedrekord.HashedrekordV001Schema( 275 signature=rekor_types.hashedrekord.Signature( 276 content=base64.b64encode(artifact_signature).decode(), 277 public_key=rekor_types.hashedrekord.PublicKey( 278 content=b64_cert.decode() 279 ), 280 ), 281 data=rekor_types.hashedrekord.Data( 282 hash=rekor_types.hashedrekord.Hash( 283 algorithm=hashed_input._as_hashedrekord_algorithm(), 284 value=hashed_input.digest.hex(), 285 ) 286 ), 287 ), 288 ) 289 290 return self._finalize_sign(cert, content, proposed_entry) 291 292 293class SigningContext: 294 """ 295 Keep a context between signing operations. 296 """ 297 298 def __init__( 299 self, *, fulcio: FulcioClient, rekor: RekorClient, trusted_root: TrustedRoot 300 ): 301 """ 302 Create a new `SigningContext`. 303 304 `fulcio` is a `FulcioClient` capable of connecting to a Fulcio instance 305 and returning signing certificates. 306 307 `rekor` is a `RekorClient` capable of connecting to a Rekor instance 308 and creating transparency log entries. 309 """ 310 self._fulcio = fulcio 311 self._rekor = rekor 312 self._trusted_root = trusted_root 313 314 @classmethod 315 def production(cls) -> SigningContext: 316 """ 317 Return a `SigningContext` instance configured against Sigstore's production-level services. 318 """ 319 return cls( 320 fulcio=FulcioClient.production(), 321 rekor=RekorClient.production(), 322 trusted_root=TrustedRoot.production(), 323 ) 324 325 @classmethod 326 def staging(cls) -> SigningContext: 327 """ 328 Return a `SignerContext` instance configured against Sigstore's staging-level services. 329 """ 330 return cls( 331 fulcio=FulcioClient.staging(), 332 rekor=RekorClient.staging(), 333 trusted_root=TrustedRoot.staging(), 334 ) 335 336 @classmethod 337 def _from_trust_config(cls, trust_config: ClientTrustConfig) -> SigningContext: 338 """ 339 Create a `SigningContext` from the given `ClientTrustConfig`. 340 341 @api private 342 """ 343 return cls( 344 fulcio=FulcioClient(trust_config._inner.signing_config.ca_url), 345 rekor=RekorClient(trust_config._inner.signing_config.tlog_urls[0]), 346 trusted_root=trust_config.trusted_root, 347 ) 348 349 @contextmanager 350 def signer( 351 self, identity_token: IdentityToken, *, cache: bool = True 352 ) -> Iterator[Signer]: 353 """ 354 A context manager for signing operations. 355 356 `identity_token` is the identity token passed to the `Signer` instance 357 and used to request a signing certificate from Fulcio. 358 359 `cache` determines whether the signing certificate and ephemeral private key 360 generated by the `Signer` instance should be reused (until the certificate expires) 361 to sign different artifacts. 362 Default is `True`. 363 """ 364 yield Signer(identity_token, self, cache)
74class Signer: 75 """ 76 The primary API for signing operations. 77 """ 78 79 def __init__( 80 self, 81 identity_token: IdentityToken, 82 signing_ctx: SigningContext, 83 cache: bool = True, 84 ) -> None: 85 """ 86 Create a new `Signer`. 87 88 `identity_token` is the identity token used to request a signing certificate 89 from Fulcio. 90 91 `signing_ctx` is a `SigningContext` that keeps information about the signing 92 configuration. 93 94 `cache` determines whether the signing certificate and ephemeral private key 95 should be reused (until the certificate expires) to sign different artifacts. 96 Default is `True`. 97 """ 98 self._identity_token = identity_token 99 self._signing_ctx: SigningContext = signing_ctx 100 self.__cached_private_key: Optional[ec.EllipticCurvePrivateKey] = None 101 self.__cached_signing_certificate: Optional[x509.Certificate] = None 102 if cache: 103 _logger.debug("Generating ephemeral keys...") 104 self.__cached_private_key = ec.generate_private_key(ec.SECP256R1()) 105 _logger.debug("Requesting ephemeral certificate...") 106 self.__cached_signing_certificate = self._signing_cert() 107 108 @property 109 def _private_key(self) -> ec.EllipticCurvePrivateKey: 110 """Get or generate a signing key.""" 111 if self.__cached_private_key is None: 112 _logger.debug("no cached key; generating ephemeral key") 113 return ec.generate_private_key(ec.SECP256R1()) 114 return self.__cached_private_key 115 116 def _signing_cert( 117 self, 118 ) -> x509.Certificate: 119 """ 120 Get or request a signing certificate from Fulcio. 121 122 Internally, this performs a CSR against Fulcio and verifies that 123 the returned certificate is present in Fulcio's CT log. 124 """ 125 126 # Our CSR cannot possibly succeed if our underlying identity token 127 # is expired. 128 if not self._identity_token.in_validity_period(): 129 raise ExpiredIdentity 130 131 # If it exists, verify if the current certificate is expired 132 if self.__cached_signing_certificate: 133 not_valid_after = self.__cached_signing_certificate.not_valid_after_utc 134 if datetime.now(timezone.utc) > not_valid_after: 135 raise ExpiredCertificate 136 return self.__cached_signing_certificate 137 138 else: 139 _logger.debug("Retrieving signed certificate...") 140 141 # Build an X.509 Certificiate Signing Request 142 builder = ( 143 x509.CertificateSigningRequestBuilder() 144 .subject_name( 145 x509.Name( 146 [ 147 x509.NameAttribute( 148 NameOID.EMAIL_ADDRESS, self._identity_token._identity 149 ), 150 ] 151 ) 152 ) 153 .add_extension( 154 x509.BasicConstraints(ca=False, path_length=None), 155 critical=True, 156 ) 157 ) 158 certificate_request = builder.sign(self._private_key, hashes.SHA256()) 159 160 certificate_response = self._signing_ctx._fulcio.signing_cert.post( 161 certificate_request, self._identity_token 162 ) 163 164 # Verify the SCT 165 sct = certificate_response.sct 166 cert = certificate_response.cert 167 chain = certificate_response.chain 168 169 verify_sct( 170 sct, 171 cert, 172 chain, 173 self._signing_ctx._trusted_root.ct_keyring(KeyringPurpose.SIGN), 174 ) 175 176 _logger.debug("Successfully verified SCT...") 177 178 return cert 179 180 def _finalize_sign( 181 self, 182 cert: x509.Certificate, 183 content: MessageSignature | dsse.Envelope, 184 proposed_entry: rekor_types.Hashedrekord | rekor_types.Dsse, 185 ) -> Bundle: 186 """ 187 Perform the common "finalizing" steps in a Sigstore signing flow. 188 """ 189 # Submit the proposed entry to the transparency log 190 entry = self._signing_ctx._rekor.log.entries.post(proposed_entry) 191 192 _logger.debug(f"Transparency log entry created with index: {entry.log_index}") 193 194 return Bundle._from_parts(cert, content, entry) 195 196 def sign_dsse( 197 self, 198 input_: dsse.Statement, 199 ) -> Bundle: 200 """ 201 Sign the given in-toto statement as a DSSE envelope, and return a 202 `Bundle` containing the signed result. 203 204 This API is **only** for in-toto statements; to sign arbitrary artifacts, 205 use `sign_artifact` instead. 206 """ 207 cert = self._signing_cert() 208 209 # Prepare inputs 210 b64_cert = base64.b64encode( 211 cert.public_bytes(encoding=serialization.Encoding.PEM) 212 ) 213 214 # Sign the statement, producing a DSSE envelope 215 content = dsse._sign(self._private_key, input_) 216 217 # Create the proposed DSSE log entry 218 proposed_entry = rekor_types.Dsse( 219 spec=rekor_types.dsse.DsseSchema( 220 # NOTE: mypy can't see that this kwarg is correct due to two interacting 221 # behaviors/bugs (one pydantic, one datamodel-codegen): 222 # See: <https://github.com/pydantic/pydantic/discussions/7418#discussioncomment-9024927> 223 # See: <https://github.com/koxudaxi/datamodel-code-generator/issues/1903> 224 proposed_content=rekor_types.dsse.ProposedContent( # type: ignore[call-arg] 225 envelope=content.to_json(), 226 verifiers=[b64_cert.decode()], 227 ), 228 ), 229 ) 230 231 return self._finalize_sign(cert, content, proposed_entry) 232 233 def sign_artifact( 234 self, 235 input_: bytes | sigstore_hashes.Hashed, 236 ) -> Bundle: 237 """ 238 Sign an artifact, and return a `Bundle` corresponding to the signed result. 239 240 The input can be one of two forms: 241 242 1. A `bytes` buffer; 243 2. A `Hashed` object, containing a pre-hashed input (e.g., for inputs 244 that are too large to buffer into memory). 245 246 Regardless of the input format, the signing operation will produce a 247 `hashedrekord` entry within the bundle. No other entry types 248 are supported by this API. 249 """ 250 251 cert = self._signing_cert() 252 253 # Prepare inputs 254 b64_cert = base64.b64encode( 255 cert.public_bytes(encoding=serialization.Encoding.PEM) 256 ) 257 258 # Sign artifact 259 hashed_input = sha256_digest(input_) 260 261 artifact_signature = self._private_key.sign( 262 hashed_input.digest, ec.ECDSA(hashed_input._as_prehashed()) 263 ) 264 265 content = MessageSignature( 266 message_digest=HashOutput( 267 algorithm=hashed_input.algorithm, 268 digest=hashed_input.digest, 269 ), 270 signature=artifact_signature, 271 ) 272 273 # Create the proposed hashedrekord entry 274 proposed_entry = rekor_types.Hashedrekord( 275 spec=rekor_types.hashedrekord.HashedrekordV001Schema( 276 signature=rekor_types.hashedrekord.Signature( 277 content=base64.b64encode(artifact_signature).decode(), 278 public_key=rekor_types.hashedrekord.PublicKey( 279 content=b64_cert.decode() 280 ), 281 ), 282 data=rekor_types.hashedrekord.Data( 283 hash=rekor_types.hashedrekord.Hash( 284 algorithm=hashed_input._as_hashedrekord_algorithm(), 285 value=hashed_input.digest.hex(), 286 ) 287 ), 288 ), 289 ) 290 291 return self._finalize_sign(cert, content, proposed_entry)
The primary API for signing operations.
79 def __init__( 80 self, 81 identity_token: IdentityToken, 82 signing_ctx: SigningContext, 83 cache: bool = True, 84 ) -> None: 85 """ 86 Create a new `Signer`. 87 88 `identity_token` is the identity token used to request a signing certificate 89 from Fulcio. 90 91 `signing_ctx` is a `SigningContext` that keeps information about the signing 92 configuration. 93 94 `cache` determines whether the signing certificate and ephemeral private key 95 should be reused (until the certificate expires) to sign different artifacts. 96 Default is `True`. 97 """ 98 self._identity_token = identity_token 99 self._signing_ctx: SigningContext = signing_ctx 100 self.__cached_private_key: Optional[ec.EllipticCurvePrivateKey] = None 101 self.__cached_signing_certificate: Optional[x509.Certificate] = None 102 if cache: 103 _logger.debug("Generating ephemeral keys...") 104 self.__cached_private_key = ec.generate_private_key(ec.SECP256R1()) 105 _logger.debug("Requesting ephemeral certificate...") 106 self.__cached_signing_certificate = self._signing_cert()
Create a new Signer
.
identity_token
is the identity token used to request a signing certificate
from Fulcio.
signing_ctx
is a SigningContext
that keeps information about the signing
configuration.
cache
determines whether the signing certificate and ephemeral private key
should be reused (until the certificate expires) to sign different artifacts.
Default is True
.
196 def sign_dsse( 197 self, 198 input_: dsse.Statement, 199 ) -> Bundle: 200 """ 201 Sign the given in-toto statement as a DSSE envelope, and return a 202 `Bundle` containing the signed result. 203 204 This API is **only** for in-toto statements; to sign arbitrary artifacts, 205 use `sign_artifact` instead. 206 """ 207 cert = self._signing_cert() 208 209 # Prepare inputs 210 b64_cert = base64.b64encode( 211 cert.public_bytes(encoding=serialization.Encoding.PEM) 212 ) 213 214 # Sign the statement, producing a DSSE envelope 215 content = dsse._sign(self._private_key, input_) 216 217 # Create the proposed DSSE log entry 218 proposed_entry = rekor_types.Dsse( 219 spec=rekor_types.dsse.DsseSchema( 220 # NOTE: mypy can't see that this kwarg is correct due to two interacting 221 # behaviors/bugs (one pydantic, one datamodel-codegen): 222 # See: <https://github.com/pydantic/pydantic/discussions/7418#discussioncomment-9024927> 223 # See: <https://github.com/koxudaxi/datamodel-code-generator/issues/1903> 224 proposed_content=rekor_types.dsse.ProposedContent( # type: ignore[call-arg] 225 envelope=content.to_json(), 226 verifiers=[b64_cert.decode()], 227 ), 228 ), 229 ) 230 231 return self._finalize_sign(cert, content, proposed_entry)
Sign the given in-toto statement as a DSSE envelope, and return a
Bundle
containing the signed result.
This API is only for in-toto statements; to sign arbitrary artifacts,
use sign_artifact
instead.
233 def sign_artifact( 234 self, 235 input_: bytes | sigstore_hashes.Hashed, 236 ) -> Bundle: 237 """ 238 Sign an artifact, and return a `Bundle` corresponding to the signed result. 239 240 The input can be one of two forms: 241 242 1. A `bytes` buffer; 243 2. A `Hashed` object, containing a pre-hashed input (e.g., for inputs 244 that are too large to buffer into memory). 245 246 Regardless of the input format, the signing operation will produce a 247 `hashedrekord` entry within the bundle. No other entry types 248 are supported by this API. 249 """ 250 251 cert = self._signing_cert() 252 253 # Prepare inputs 254 b64_cert = base64.b64encode( 255 cert.public_bytes(encoding=serialization.Encoding.PEM) 256 ) 257 258 # Sign artifact 259 hashed_input = sha256_digest(input_) 260 261 artifact_signature = self._private_key.sign( 262 hashed_input.digest, ec.ECDSA(hashed_input._as_prehashed()) 263 ) 264 265 content = MessageSignature( 266 message_digest=HashOutput( 267 algorithm=hashed_input.algorithm, 268 digest=hashed_input.digest, 269 ), 270 signature=artifact_signature, 271 ) 272 273 # Create the proposed hashedrekord entry 274 proposed_entry = rekor_types.Hashedrekord( 275 spec=rekor_types.hashedrekord.HashedrekordV001Schema( 276 signature=rekor_types.hashedrekord.Signature( 277 content=base64.b64encode(artifact_signature).decode(), 278 public_key=rekor_types.hashedrekord.PublicKey( 279 content=b64_cert.decode() 280 ), 281 ), 282 data=rekor_types.hashedrekord.Data( 283 hash=rekor_types.hashedrekord.Hash( 284 algorithm=hashed_input._as_hashedrekord_algorithm(), 285 value=hashed_input.digest.hex(), 286 ) 287 ), 288 ), 289 ) 290 291 return self._finalize_sign(cert, content, proposed_entry)
Sign an artifact, and return a Bundle
corresponding to the signed result.
The input can be one of two forms:
- A
bytes
buffer; - A
Hashed
object, containing a pre-hashed input (e.g., for inputs that are too large to buffer into memory).
Regardless of the input format, the signing operation will produce a
hashedrekord
entry within the bundle. No other entry types
are supported by this API.
294class SigningContext: 295 """ 296 Keep a context between signing operations. 297 """ 298 299 def __init__( 300 self, *, fulcio: FulcioClient, rekor: RekorClient, trusted_root: TrustedRoot 301 ): 302 """ 303 Create a new `SigningContext`. 304 305 `fulcio` is a `FulcioClient` capable of connecting to a Fulcio instance 306 and returning signing certificates. 307 308 `rekor` is a `RekorClient` capable of connecting to a Rekor instance 309 and creating transparency log entries. 310 """ 311 self._fulcio = fulcio 312 self._rekor = rekor 313 self._trusted_root = trusted_root 314 315 @classmethod 316 def production(cls) -> SigningContext: 317 """ 318 Return a `SigningContext` instance configured against Sigstore's production-level services. 319 """ 320 return cls( 321 fulcio=FulcioClient.production(), 322 rekor=RekorClient.production(), 323 trusted_root=TrustedRoot.production(), 324 ) 325 326 @classmethod 327 def staging(cls) -> SigningContext: 328 """ 329 Return a `SignerContext` instance configured against Sigstore's staging-level services. 330 """ 331 return cls( 332 fulcio=FulcioClient.staging(), 333 rekor=RekorClient.staging(), 334 trusted_root=TrustedRoot.staging(), 335 ) 336 337 @classmethod 338 def _from_trust_config(cls, trust_config: ClientTrustConfig) -> SigningContext: 339 """ 340 Create a `SigningContext` from the given `ClientTrustConfig`. 341 342 @api private 343 """ 344 return cls( 345 fulcio=FulcioClient(trust_config._inner.signing_config.ca_url), 346 rekor=RekorClient(trust_config._inner.signing_config.tlog_urls[0]), 347 trusted_root=trust_config.trusted_root, 348 ) 349 350 @contextmanager 351 def signer( 352 self, identity_token: IdentityToken, *, cache: bool = True 353 ) -> Iterator[Signer]: 354 """ 355 A context manager for signing operations. 356 357 `identity_token` is the identity token passed to the `Signer` instance 358 and used to request a signing certificate from Fulcio. 359 360 `cache` determines whether the signing certificate and ephemeral private key 361 generated by the `Signer` instance should be reused (until the certificate expires) 362 to sign different artifacts. 363 Default is `True`. 364 """ 365 yield Signer(identity_token, self, cache)
Keep a context between signing operations.
299 def __init__( 300 self, *, fulcio: FulcioClient, rekor: RekorClient, trusted_root: TrustedRoot 301 ): 302 """ 303 Create a new `SigningContext`. 304 305 `fulcio` is a `FulcioClient` capable of connecting to a Fulcio instance 306 and returning signing certificates. 307 308 `rekor` is a `RekorClient` capable of connecting to a Rekor instance 309 and creating transparency log entries. 310 """ 311 self._fulcio = fulcio 312 self._rekor = rekor 313 self._trusted_root = trusted_root
Create a new SigningContext
.
fulcio
is a FulcioClient
capable of connecting to a Fulcio instance
and returning signing certificates.
rekor
is a RekorClient
capable of connecting to a Rekor instance
and creating transparency log entries.
315 @classmethod 316 def production(cls) -> SigningContext: 317 """ 318 Return a `SigningContext` instance configured against Sigstore's production-level services. 319 """ 320 return cls( 321 fulcio=FulcioClient.production(), 322 rekor=RekorClient.production(), 323 trusted_root=TrustedRoot.production(), 324 )
Return a SigningContext
instance configured against Sigstore's production-level services.
326 @classmethod 327 def staging(cls) -> SigningContext: 328 """ 329 Return a `SignerContext` instance configured against Sigstore's staging-level services. 330 """ 331 return cls( 332 fulcio=FulcioClient.staging(), 333 rekor=RekorClient.staging(), 334 trusted_root=TrustedRoot.staging(), 335 )
Return a SignerContext
instance configured against Sigstore's staging-level services.
350 @contextmanager 351 def signer( 352 self, identity_token: IdentityToken, *, cache: bool = True 353 ) -> Iterator[Signer]: 354 """ 355 A context manager for signing operations. 356 357 `identity_token` is the identity token passed to the `Signer` instance 358 and used to request a signing certificate from Fulcio. 359 360 `cache` determines whether the signing certificate and ephemeral private key 361 generated by the `Signer` instance should be reused (until the certificate expires) 362 to sign different artifacts. 363 Default is `True`. 364 """ 365 yield Signer(identity_token, self, cache)
A context manager for signing operations.
identity_token
is the identity token passed to the Signer
instance
and used to request a signing certificate from Fulcio.
cache
determines whether the signing certificate and ephemeral private key
generated by the Signer
instance should be reused (until the certificate expires)
to sign different artifacts.
Default is True
.