From 2c9a4ffc289858ba80209600f581961be1a49b83 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Wed, 30 Apr 2025 10:28:38 +0300 Subject: [PATCH 01/17] cli: Get OIDC url from trust config This is not super useful at this point as the TUF repositories do not have the required signing config yet so we can't simplify the code yet: The goal is still for trustconfig to be the only source configuration like the OIDC URL. Signed-off-by: Jussi Kukkonen --- sigstore/_cli.py | 39 ++++++++++++++++++++++++++++----------- sigstore/oidc.py | 8 ++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/sigstore/_cli.py b/sigstore/_cli.py index 480512e63..43692af05 100644 --- a/sigstore/_cli.py +++ b/sigstore/_cli.py @@ -614,11 +614,7 @@ def main(args: list[str] | None = None) -> None: elif args.verify_subcommand == "github": _verify_github(args) elif args.subcommand == "get-identity-token": - identity = _get_identity(args) - if identity: - print(identity) - else: - _invalid_arguments(args, "No identity token supplied or detected!") + _get_identity_token(args) elif args.subcommand == "plumbing": if args.plumbing_subcommand == "fix-bundle": _fix_bundle(args) @@ -630,6 +626,21 @@ def main(args: list[str] | None = None) -> None: e.log_and_exit(_logger, args.verbose >= 1) +def _get_identity_token(args: argparse.Namespace) -> None: + """ + Output the OIDC authentication token + """ + + trust_config: ClientTrustConfig | None = None + if args.trust_config: + trust_config = ClientTrustConfig.from_json(args.trust_config.read_text()) + identity = _get_identity(args, trust_config) + if identity: + print(identity) + else: + _invalid_arguments(args, "No identity token supplied or detected!") + + def _sign_common( args: argparse.Namespace, output_map: OutputMap, predicate: dict[str, Any] | None ) -> None: @@ -643,16 +654,18 @@ def _sign_common( not, it will use a hashedrekord. """ # Select the signing context to use. - if args.staging: - _logger.debug("sign: staging instances requested") - signing_ctx = SigningContext.staging() - elif args.trust_config: + if args.trust_config: trust_config = ClientTrustConfig.from_json(args.trust_config.read_text()) signing_ctx = SigningContext._from_trust_config(trust_config) + elif args.staging: + _logger.debug("sign: staging instances requested") + trust_config = None # signingconfig 0.2 is not in staging TUF yet + signing_ctx = SigningContext.staging() else: # If the user didn't request the staging instance or pass in an # explicit client trust config, we're using the public good (i.e. # production) instance. + trust_config = None # signingconfig 0.2 is not in staging TUF yet signing_ctx = SigningContext.production() # The order of precedence for identities is as follows: @@ -664,7 +677,7 @@ def _sign_common( if args.identity_token: identity = IdentityToken(args.identity_token) else: - identity = _get_identity(args) + identity = _get_identity(args, trust_config) if not identity: _invalid_arguments(args, "No identity token supplied or detected!") @@ -1167,7 +1180,9 @@ def _verify_common( return None -def _get_identity(args: argparse.Namespace) -> Optional[IdentityToken]: +def _get_identity( + args: argparse.Namespace, trust_config: ClientTrustConfig | None +) -> Optional[IdentityToken]: token = None if not args.oidc_disable_ambient_providers: token = detect_credential() @@ -1176,6 +1191,8 @@ def _get_identity(args: argparse.Namespace) -> Optional[IdentityToken]: if token: return IdentityToken(token) + if trust_config is not None: + issuer = Issuer.from_trust_config(trust_config) if args.staging: issuer = Issuer.staging() elif args.oidc_issuer == DEFAULT_OAUTH_ISSUER_URL: diff --git a/sigstore/oidc.py b/sigstore/oidc.py index c401dff59..5149e909d 100644 --- a/sigstore/oidc.py +++ b/sigstore/oidc.py @@ -32,6 +32,7 @@ from pydantic import BaseModel, StrictStr from sigstore._internal import USER_AGENT +from sigstore._internal.trust import ClientTrustConfig from sigstore.errors import Error, NetworkError DEFAULT_OAUTH_ISSUER_URL = "https://oauth2.sigstore.dev/auth" @@ -285,6 +286,13 @@ def staging(cls) -> Issuer: """ return cls(STAGING_OAUTH_ISSUER_URL) + @classmethod + def from_trust_config(cls, trust_config: ClientTrustConfig) -> Issuer: + """ + Return `Issuer` for given `ClientTrustConfig`. + """ + return cls(trust_config.signing_config.get_oidc_url()) + def identity_token( # nosec: B107 self, client_id: str = "sigstore", From 750547dc9ceb6cbc9ca856fb28e75c0a934ab37b Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Wed, 30 Apr 2025 13:40:50 +0300 Subject: [PATCH 02/17] trust: Provide methods to load TrustConfig from tuf We have previously done this for TrustedRoot but doing this for the whole TrustConfig makes sense. The only complication is that production instance does not have the SigningConfig component yet so we need to provide a fallback for that. Signed-off-by: Jussi Kukkonen --- sigstore/_internal/trust.py | 60 ++++++++++++++++++- sigstore/_internal/tuf.py | 23 +++++++ sigstore/_store/prod/signing_config.v0.2.json | 38 ++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 sigstore/_store/prod/signing_config.v0.2.json diff --git a/sigstore/_internal/trust.py b/sigstore/_internal/trust.py index 712eb0121..9a064fb93 100644 --- a/sigstore/_internal/trust.py +++ b/sigstore/_internal/trust.py @@ -62,8 +62,9 @@ PublicKey, key_id, load_der_public_key, + read_embedded, ) -from sigstore.errors import Error, MetadataError, VerificationError +from sigstore.errors import Error, MetadataError, TUFError, VerificationError def _is_timerange_valid(period: TimeRange | None, *, allow_expired: bool) -> bool: @@ -559,6 +560,63 @@ def from_json(cls, raw: str) -> ClientTrustConfig: inner = _ClientTrustConfig().from_json(raw) return cls(inner) + @classmethod + def production( + cls, + offline: bool = False, + ) -> ClientTrustConfig: + """Create new trust config from Sigstore production TUF repository. + + If `offline`, will use data in local TUF cache. Otherwise will + update the data from remote TUF repository. + """ + return cls.from_tuf(DEFAULT_TUF_URL, offline) + + @classmethod + def staging( + cls, + offline: bool = False, + ) -> ClientTrustConfig: + """Create new trust config from Sigstore staging TUF repository. + + If `offline`, will use data in local TUF cache. Otherwise will + update the data from remote TUF repository. + """ + return cls.from_tuf(STAGING_TUF_URL, offline) + + @classmethod + def from_tuf( + cls, + url: str, + offline: bool = False, + ) -> ClientTrustConfig: + """Create a new trust config from a TUF repository. + + If `offline`, will use data in local TUF cache. Otherwise will + update the trust config from remote TUF repository. + """ + updater = TrustUpdater(url, offline) + + tr_path = updater.get_trusted_root_path() + inner_tr = _TrustedRoot().from_json(Path(tr_path).read_bytes()) + + try: + sc_path = updater.get_signing_config_path() + inner_sc = _SigningConfig().from_json(Path(sc_path).read_bytes()) + except TUFError as e: + # TUF repo may not have signing config yet: hard code values for prod: + if url == DEFAULT_TUF_URL: + embedded = read_embedded("signing_config.v0.2.json", "prod") + inner_sc = _SigningConfig().from_json(embedded) + else: + raise e + + return _ClientTrustConfig( + ClientTrustConfig.ClientTrustConfigType.CONFIG_0_1, + inner_tr, + inner_sc, + ) + def __init__(self, inner: _ClientTrustConfig) -> None: """ @api private diff --git a/sigstore/_internal/tuf.py b/sigstore/_internal/tuf.py index 265be87a0..115f44b54 100644 --- a/sigstore/_internal/tuf.py +++ b/sigstore/_internal/tuf.py @@ -148,3 +148,26 @@ def get_trusted_root_path(self) -> str: _logger.debug("Found and verified trusted root") return path + + @lru_cache() + def get_signing_config_path(self) -> str: + """Return local path to currently valid signing config file""" + if not self._updater: + _logger.debug("Using unverified signing config from cache") + return str(self._targets_dir / "signing_config.v0.2.json") + + root_info = self._updater.get_targetinfo("signing_config.v0.2.json") + if root_info is None: + raise TUFError("Unsupported TUF configuration: no signing config") + path = self._updater.find_cached_target(root_info) + if path is None: + try: + path = self._updater.download_target(root_info) + except ( + TUFExceptions.DownloadError, + TUFExceptions.RepositoryError, + ) as e: + raise TUFError("Failed to download trusted key bundle") from e + + _logger.debug("Found and verified signing config") + return path diff --git a/sigstore/_store/prod/signing_config.v0.2.json b/sigstore/_store/prod/signing_config.v0.2.json new file mode 100644 index 000000000..dc4ae078b --- /dev/null +++ b/sigstore/_store/prod/signing_config.v0.2.json @@ -0,0 +1,38 @@ +{ + "mediaType": "application/vnd.dev.sigstore.signingconfig.v0.2+json", + "caUrls": [ + { + "url": "https://fulcio.sigstore.dev", + "majorApiVersion": 1, + "validFor": { + "start": "2022-04-13T20:06:15.000Z" + } + } + ], + "oidcUrls": [ + { + "url": "https://oauth2.sigstore.dev/auth", + "majorApiVersion": 1, + "validFor": { + "start": "2025-04-30T00:00:00Z" + } + } + ], + "rekorTlogUrls": [ + { + "url": "https://rekor.sigstore.dev", + "majorApiVersion": 1, + "validFor": { + "start": "2021-01-12T11:53:27.000Z" + } + } + ], + "tsaUrls": [ + ], + "rekorTlogConfig": { + "selector": "ANY" + }, + "tsaConfig": { + "selector": "ANY" + } +} \ No newline at end of file From 05cc6339908f4a3f2ffab582f5283c615f7ec282 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Wed, 30 Apr 2025 14:36:57 +0300 Subject: [PATCH 03/17] Use TrustConfig to initialize components This change makes almost all code paths now use TrustConfig to choose the sigstore instance (urls, keys, validity periods, etc). * OIDC url now comes from signingconfig too * Some production()/staging() methods remain because they're used by tests or special cases like "fix-bundle" * Likewise some hard coded urls are left in the code since they are used by some special case Signed-off-by: Jussi Kukkonen --- sigstore/_cli.py | 75 +++++++++++--------------- sigstore/_internal/fulcio/client.py | 18 +------ sigstore/_internal/trust.py | 10 ++-- sigstore/oidc.py | 17 ------ sigstore/sign.py | 24 +-------- sigstore/verify/verifier.py | 13 +---- test/unit/internal/oidc/test_issuer.py | 2 +- test/unit/test_sign.py | 11 +--- 8 files changed, 42 insertions(+), 128 deletions(-) diff --git a/sigstore/_cli.py b/sigstore/_cli.py index 43692af05..d74dc8623 100644 --- a/sigstore/_cli.py +++ b/sigstore/_cli.py @@ -39,7 +39,7 @@ from sigstore._internal.fulcio.client import ExpiredCertificate from sigstore._internal.rekor import _hashedrekord_from_parts from sigstore._internal.rekor.client import RekorClient -from sigstore._internal.trust import ClientTrustConfig, TrustedRoot +from sigstore._internal.trust import ClientTrustConfig from sigstore._utils import sha256_digest from sigstore.dsse import StatementBuilder, Subject from sigstore.dsse._predicate import ( @@ -51,7 +51,6 @@ from sigstore.hashes import Hashed from sigstore.models import Bundle, InvalidBundle from sigstore.oidc import ( - DEFAULT_OAUTH_ISSUER_URL, ExpiredIdentity, IdentityToken, Issuer, @@ -229,8 +228,8 @@ def _add_shared_oidc_options( "--oidc-issuer", metavar="URL", type=str, - default=os.getenv("SIGSTORE_OIDC_ISSUER", DEFAULT_OAUTH_ISSUER_URL), - help="The OpenID Connect issuer to use (conflicts with --staging)", + default=os.getenv("SIGSTORE_OIDC_ISSUER", None), + help="The OpenID Connect issuer to use", ) group.add_argument( "--oauth-force-oob", @@ -630,11 +629,7 @@ def _get_identity_token(args: argparse.Namespace) -> None: """ Output the OIDC authentication token """ - - trust_config: ClientTrustConfig | None = None - if args.trust_config: - trust_config = ClientTrustConfig.from_json(args.trust_config.read_text()) - identity = _get_identity(args, trust_config) + identity = _get_identity(args, _get_trust_config(args)) if identity: print(identity) else: @@ -654,19 +649,8 @@ def _sign_common( not, it will use a hashedrekord. """ # Select the signing context to use. - if args.trust_config: - trust_config = ClientTrustConfig.from_json(args.trust_config.read_text()) - signing_ctx = SigningContext._from_trust_config(trust_config) - elif args.staging: - _logger.debug("sign: staging instances requested") - trust_config = None # signingconfig 0.2 is not in staging TUF yet - signing_ctx = SigningContext.staging() - else: - # If the user didn't request the staging instance or pass in an - # explicit client trust config, we're using the public good (i.e. - # production) instance. - trust_config = None # signingconfig 0.2 is not in staging TUF yet - signing_ctx = SigningContext.production() + trust_config = _get_trust_config(args) + signing_ctx = SigningContext.from_trust_config(trust_config) # The order of precedence for identities is as follows: # @@ -1022,14 +1006,8 @@ def _collect_verification_state( f"Missing verification materials for {(hashed)}: {', '.join(missing)}", ) - if args.staging: - _logger.debug("verify: staging instances requested") - verifier = Verifier.staging(offline=args.offline) - elif args.trust_config: - trust_config = ClientTrustConfig.from_json(args.trust_config.read_text()) - verifier = Verifier._from_trust_config(trust_config) - else: - verifier = Verifier.production(offline=args.offline) + trust_config = _get_trust_config(args) + verifier = Verifier(trusted_root=trust_config.trusted_root) all_materials = [] for file_or_hashed, materials in input_map.items(): @@ -1180,8 +1158,23 @@ def _verify_common( return None +def _get_trust_config(args: argparse.Namespace) -> ClientTrustConfig: + """ + Return the client trust configuration (Sigstore service URLs, key material and lifetimes) + + The configuration may come from explicit argument (--trust-config) or from the TUF + repository of the used Sigstore instance. + """ + if args.trust_config: + return ClientTrustConfig.from_json(args.trust_config.read_text()) + elif args.staging: + return ClientTrustConfig.staging(offline=args.offline) + else: + return ClientTrustConfig.production(offline=args.offline) + + def _get_identity( - args: argparse.Namespace, trust_config: ClientTrustConfig | None + args: argparse.Namespace, trust_config: ClientTrustConfig ) -> Optional[IdentityToken]: token = None if not args.oidc_disable_ambient_providers: @@ -1191,14 +1184,10 @@ def _get_identity( if token: return IdentityToken(token) - if trust_config is not None: - issuer = Issuer.from_trust_config(trust_config) - if args.staging: - issuer = Issuer.staging() - elif args.oidc_issuer == DEFAULT_OAUTH_ISSUER_URL: - issuer = Issuer.production() - else: + if args.oidc_issuer is not None: issuer = Issuer(args.oidc_issuer) + else: + issuer = Issuer.from_trust_config(trust_config) if args.oidc_client_secret is None: args.oidc_client_secret = "" # nosec: B105 @@ -1215,6 +1204,7 @@ def _get_identity( def _fix_bundle(args: argparse.Namespace) -> None: # NOTE: We could support `--trusted-root` here in the future, # for custom Rekor instances. + rekor = RekorClient.staging() if args.staging else RekorClient.production() raw_bundle = RawBundle.from_dict(json.loads(args.bundle.read_bytes())) @@ -1251,13 +1241,10 @@ def _fix_bundle(args: argparse.Namespace) -> None: def _update_trust_root(args: argparse.Namespace) -> None: - # Simply creating the TrustedRoot in online mode is enough to perform + # Simply creating the TrustConfig in online mode is enough to perform # a metadata update. - if args.staging: - trusted_root = TrustedRoot.staging(offline=False) - else: - trusted_root = TrustedRoot.production(offline=False) + config = _get_trust_config(args) _console.print( - f"Trust root updated: {len(trusted_root.get_fulcio_certs())} Fulcio certificates" + f"Trust root & signing config updated: {len(config.trusted_root.get_fulcio_certs())} Fulcio certificates" ) diff --git a/sigstore/_internal/fulcio/client.py b/sigstore/_internal/fulcio/client.py index 0552628d1..75da5114f 100644 --- a/sigstore/_internal/fulcio/client.py +++ b/sigstore/_internal/fulcio/client.py @@ -39,8 +39,6 @@ _logger = logging.getLogger(__name__) -DEFAULT_FULCIO_URL = "https://fulcio.sigstore.dev" -STAGING_FULCIO_URL = "https://fulcio.sigstage.dev" SIGNING_CERT_ENDPOINT = "/api/v2/signingCert" TRUST_BUNDLE_ENDPOINT = "/api/v2/trustBundle" @@ -163,7 +161,7 @@ def get(self) -> FulcioTrustBundleResponse: class FulcioClient: """The internal Fulcio client""" - def __init__(self, url: str = DEFAULT_FULCIO_URL) -> None: + def __init__(self, url: str) -> None: """Initialize the client""" _logger.debug(f"Fulcio client using URL: {url}") self.url = url @@ -180,20 +178,6 @@ def __del__(self) -> None: """ self.session.close() - @classmethod - def production(cls) -> FulcioClient: - """ - Returns a `FulcioClient` for the Sigstore production instance of Fulcio. - """ - return cls(DEFAULT_FULCIO_URL) - - @classmethod - def staging(cls) -> FulcioClient: - """ - Returns a `FulcioClient` for the Sigstore staging instance of Fulcio. - """ - return cls(STAGING_FULCIO_URL) - @property def signing_cert(self) -> FulcioSigningCert: """ diff --git a/sigstore/_internal/trust.py b/sigstore/_internal/trust.py index 9a064fb93..d350cd048 100644 --- a/sigstore/_internal/trust.py +++ b/sigstore/_internal/trust.py @@ -611,10 +611,12 @@ def from_tuf( else: raise e - return _ClientTrustConfig( - ClientTrustConfig.ClientTrustConfigType.CONFIG_0_1, - inner_tr, - inner_sc, + return cls( + _ClientTrustConfig( + ClientTrustConfig.ClientTrustConfigType.CONFIG_0_1, + inner_tr, + inner_sc, + ) ) def __init__(self, inner: _ClientTrustConfig) -> None: diff --git a/sigstore/oidc.py b/sigstore/oidc.py index 5149e909d..c65fb8514 100644 --- a/sigstore/oidc.py +++ b/sigstore/oidc.py @@ -35,9 +35,6 @@ from sigstore._internal.trust import ClientTrustConfig from sigstore.errors import Error, NetworkError -DEFAULT_OAUTH_ISSUER_URL = "https://oauth2.sigstore.dev/auth" -STAGING_OAUTH_ISSUER_URL = "https://oauth2.sigstage.dev/auth" - # See: https://github.com/sigstore/fulcio/blob/b2186c0/pkg/config/config.go#L182-L201 _KNOWN_OIDC_ISSUERS = { "https://accounts.google.com": "email", @@ -272,20 +269,6 @@ def __init__(self, base_url: str) -> None: except ValueError as exc: raise IssuerError(f"OIDC issuer returned invalid configuration: {exc}") - @classmethod - def production(cls) -> Issuer: - """ - Returns an `Issuer` configured against Sigstore's production-level services. - """ - return cls(DEFAULT_OAUTH_ISSUER_URL) - - @classmethod - def staging(cls) -> Issuer: - """ - Returns an `Issuer` configured against Sigstore's staging-level services. - """ - return cls(STAGING_OAUTH_ISSUER_URL) - @classmethod def from_trust_config(cls, trust_config: ClientTrustConfig) -> Issuer: """ diff --git a/sigstore/sign.py b/sigstore/sign.py index ffe6fbdb1..643cc7960 100644 --- a/sigstore/sign.py +++ b/sigstore/sign.py @@ -324,29 +324,7 @@ def __init__( self._tsa_clients = tsa_clients or [] @classmethod - def production(cls) -> SigningContext: - """ - Return a `SigningContext` instance configured against Sigstore's production-level services. - """ - return cls( - fulcio=FulcioClient.production(), - rekor=RekorClient.production(), - trusted_root=TrustedRoot.production(), - ) - - @classmethod - def staging(cls) -> SigningContext: - """ - Return a `SignerContext` instance configured against Sigstore's staging-level services. - """ - return cls( - fulcio=FulcioClient.staging(), - rekor=RekorClient.staging(), - trusted_root=TrustedRoot.staging(), - ) - - @classmethod - def _from_trust_config(cls, trust_config: ClientTrustConfig) -> SigningContext: + def from_trust_config(cls, trust_config: ClientTrustConfig) -> SigningContext: """ Create a `SigningContext` from the given `ClientTrustConfig`. diff --git a/sigstore/verify/verifier.py b/sigstore/verify/verifier.py index 30e7e8e59..3f4542530 100644 --- a/sigstore/verify/verifier.py +++ b/sigstore/verify/verifier.py @@ -46,7 +46,7 @@ verify_sct, ) from sigstore._internal.timestamp import TimestampSource, TimestampVerificationResult -from sigstore._internal.trust import ClientTrustConfig, KeyringPurpose, TrustedRoot +from sigstore._internal.trust import KeyringPurpose, TrustedRoot from sigstore._utils import base64_encode_pem_cert, sha256_digest from sigstore.errors import VerificationError from sigstore.hashes import Hashed @@ -113,17 +113,6 @@ def staging(cls, *, offline: bool = False) -> Verifier: trusted_root=TrustedRoot.staging(offline=offline), ) - @classmethod - def _from_trust_config(cls, trust_config: ClientTrustConfig) -> Verifier: - """ - Create a `Verifier` from the given `ClientTrustConfig`. - - @api private - """ - return cls( - trusted_root=trust_config.trusted_root, - ) - def _verify_signed_timestamp( self, timestamp_response: TimeStampResponse, signature: bytes ) -> TimestampVerificationResult | None: diff --git a/test/unit/internal/oidc/test_issuer.py b/test/unit/internal/oidc/test_issuer.py index 5241c4171..fc2ae873d 100644 --- a/test/unit/internal/oidc/test_issuer.py +++ b/test/unit/internal/oidc/test_issuer.py @@ -33,4 +33,4 @@ def test_get_identity_token_bad_code(monkeypatch): monkeypatch.setattr("builtins.input", lambda _: "hunter2") with pytest.raises(IdentityError, match=r"^Token request failed with .+$"): - Issuer.staging().identity_token(force_oob=True) + Issuer("https://oauth2.sigstage.dev/auth").identity_token(force_oob=True) diff --git a/test/unit/test_sign.py b/test/unit/test_sign.py index 756748bc0..04a5be75d 100644 --- a/test/unit/test_sign.py +++ b/test/unit/test_sign.py @@ -29,15 +29,6 @@ from sigstore.verify.policy import UnsafeNoOp -class TestSigningContext: - @pytest.mark.production - def test_production(self): - assert SigningContext.production() is not None - - def test_staging(self, mock_staging_tuf): - assert SigningContext.staging() is not None - - @pytest.mark.parametrize("env", ["staging", "production"]) @pytest.mark.ambient_oidc def test_sign_rekor_entry_consistent(sign_ctx_and_ident_for_env): @@ -185,7 +176,7 @@ def sig_ctx(self, asset, tsa_url) -> SigningContext: trust_config._inner.signing_config.tsa_urls[0] = tsa_url - return SigningContext._from_trust_config(trust_config) + return SigningContext.from_trust_config(trust_config) @pytest.fixture def identity(self, staging): From 296f8b6c3298011600779d8feafbe50f47f0081c Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Wed, 30 Apr 2025 14:52:23 +0300 Subject: [PATCH 04/17] Remove tuf methods from TrustedRoot Probably makes sense to handle this in ClientTrustConfig only: less code that way. The tests will start passing once staging TUF contains signingconfig (and we have updated our test copies of staging TUF) Signed-off-by: Jussi Kukkonen --- sigstore/_internal/trust.py | 38 -------------------------------- sigstore/verify/verifier.py | 8 ++++--- test/unit/internal/test_trust.py | 16 +++++++------- 3 files changed, 13 insertions(+), 49 deletions(-) diff --git a/sigstore/_internal/trust.py b/sigstore/_internal/trust.py index d350cd048..d881d45f6 100644 --- a/sigstore/_internal/trust.py +++ b/sigstore/_internal/trust.py @@ -438,44 +438,6 @@ def from_file( inner = _TrustedRoot().from_json(Path(path).read_bytes()) return cls(inner) - @classmethod - def from_tuf( - cls, - url: str, - offline: bool = False, - ) -> TrustedRoot: - """Create a new trust root from a TUF repository. - - If `offline`, will use trust root in local TUF cache. Otherwise will - update the trust root from remote TUF repository. - """ - path = TrustUpdater(url, offline).get_trusted_root_path() - return cls.from_file(path) - - @classmethod - def production( - cls, - offline: bool = False, - ) -> TrustedRoot: - """Create new trust root from Sigstore production TUF repository. - - If `offline`, will use trust root in local TUF cache. Otherwise will - update the trust root from remote TUF repository. - """ - return cls.from_tuf(DEFAULT_TUF_URL, offline) - - @classmethod - def staging( - cls, - offline: bool = False, - ) -> TrustedRoot: - """Create new trust root from Sigstore staging TUF repository. - - If `offline`, will use trust root in local TUF cache. Otherwise will - update the trust root from remote TUF repository. - """ - return cls.from_tuf(STAGING_TUF_URL, offline) - def _get_tlog_keys( self, tlogs: list[TransparencyLogInstance], purpose: KeyringPurpose ) -> Iterable[_PublicKey]: diff --git a/sigstore/verify/verifier.py b/sigstore/verify/verifier.py index 3f4542530..0f4c0217b 100644 --- a/sigstore/verify/verifier.py +++ b/sigstore/verify/verifier.py @@ -46,7 +46,7 @@ verify_sct, ) from sigstore._internal.timestamp import TimestampSource, TimestampVerificationResult -from sigstore._internal.trust import KeyringPurpose, TrustedRoot +from sigstore._internal.trust import ClientTrustConfig, KeyringPurpose, TrustedRoot from sigstore._utils import base64_encode_pem_cert, sha256_digest from sigstore.errors import VerificationError from sigstore.hashes import Hashed @@ -96,8 +96,9 @@ def production(cls, *, offline: bool = False) -> Verifier: the verifier uses the Trusted Root in the local TUF cache. If `False`, a TUF repository refresh is attempted. """ + config = ClientTrustConfig.production(offline=offline) return cls( - trusted_root=TrustedRoot.production(offline=offline), + trusted_root=config.trusted_root, ) @classmethod @@ -109,8 +110,9 @@ def staging(cls, *, offline: bool = False) -> Verifier: the verifier uses the Trusted Root in the local TUF cache. If `False`, a TUF repository refresh is attempted. """ + config = ClientTrustConfig.staging(offline=offline) return cls( - trusted_root=TrustedRoot.staging(offline=offline), + trusted_root=config.trusted_root, ) def _verify_signed_timestamp( diff --git a/test/unit/internal/test_trust.py b/test/unit/internal/test_trust.py index 4042bf9c1..d9c1ada2e 100644 --- a/test/unit/internal/test_trust.py +++ b/test/unit/internal/test_trust.py @@ -96,7 +96,7 @@ def test_trust_root_tuf_caches_and_requests(mock_staging_tuf, tuf_dirs): # keep track of requests the TrustUpdater invoked by TrustedRoot makes reqs, fail_reqs = mock_staging_tuf - trust_root = TrustedRoot.staging() + trust_root = ClientTrustConfig.staging() # metadata was "downloaded" from staging expected = [ "root.json", @@ -126,7 +126,7 @@ def test_trust_root_tuf_caches_and_requests(mock_staging_tuf, tuf_dirs): assert fail_reqs == expected_fail_reqs # New trust root (and TrustUpdater instance), same cache dirs - trust_root = TrustedRoot.staging() + trust_root = ClientTrustConfig.staging() # Expect new timestamp and root requests expected_requests["timestamp.json"] += 1 @@ -148,7 +148,7 @@ def test_trust_root_tuf_offline(mock_staging_tuf, tuf_dirs): # keep track of requests the TrustUpdater invoked by TrustedRoot makes reqs, fail_reqs = mock_staging_tuf - trust_root = TrustedRoot.staging(offline=True) + trust_root = ClientTrustConfig.staging(offline=True) # local TUF metadata is not initialized, nothing is downloaded assert not os.path.exists(data_dir) @@ -217,7 +217,7 @@ def _pem_keys(keys): ] # Assert that trust root from TUF contains the expected keys/certs - trust_root = TrustedRoot.staging() + trust_root = ClientTrustConfig.staging().trusted_root assert ctfe_keys[0] in get_public_bytes( [ k.key @@ -240,7 +240,7 @@ def _pem_keys(keys): assert trust_root.get_fulcio_certs() == fulcio_certs # Assert that trust root from offline TUF contains the expected keys/certs - trust_root = TrustedRoot.staging(offline=True) + trust_root = ClientTrustConfig.staging(offline=True).trust_root assert ctfe_keys[0] in get_public_bytes( [ k.key @@ -289,18 +289,18 @@ def _pem_keys(keys): def test_trust_root_tuf_instance_error(): with pytest.raises(RootError): - TrustedRoot.from_tuf("foo.bar") + ClientTrustConfig.from_tuf("foo.bar") def test_trust_root_tuf_ctfe_keys_error(monkeypatch): - trust_root = TrustedRoot.staging(offline=True) + trust_root = ClientTrustConfig.staging(offline=True).trusted_root monkeypatch.setattr(trust_root._inner, "ctlogs", []) with pytest.raises(Exception, match="CTFE keys not found in trusted root"): trust_root.ct_keyring(purpose=KeyringPurpose.VERIFY) def test_trust_root_fulcio_certs_error(tuf_asset, monkeypatch): - trust_root = TrustedRoot.staging(offline=True) + trust_root = ClientTrustConfig.staging(offline=True).trusted_root monkeypatch.setattr(trust_root._inner, "certificate_authorities", []) with pytest.raises( Exception, match="Fulcio certificates not found in trusted root" From 91121ee9a2190fe836dd5ce79522bcb8a08aca50 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Fri, 2 May 2025 14:02:29 +0300 Subject: [PATCH 05/17] Update staging assets, refactor TUF asset lookup Commit is large just because the test and embedded assets for staging are updated. * Update the embedded data in sigstore/_store * Also update the test assets in test/assets * refactor the embedded asset lookup: use the URL to build the asset dir. This means less code duplication and easier to make this work with non-Public Good Instance TUF repos * Make the tuf module work with non-PGI instances: if the local TUF metadata is initialized out of band, tuf module just works with it. If a root.json is provided in _store, it is still always used to initialize the client Of special note is "signing_config.v0.2.json" for production: This does not actually exist yet in the TUF repository but I've added one in sigstore/_store and use it as a workaround in ClientTrustConfig.from_tuf() -- this way the code can otherwise remain identical for both staging and prod. Signed-off-by: Jussi Kukkonen --- sigstore/_internal/trust.py | 2 +- sigstore/_internal/tuf.py | 45 +++--- .../root.json | 107 +++++++++++++ .../signing_config.v0.2.json | 45 ++++++ .../trusted_root.json | 29 ++-- .../root.json | 0 .../signing_config.v0.2.json | 1 + .../trusted_root.json | 0 sigstore/_store/staging/root.json | 65 -------- sigstore/_utils.py | 10 +- test/assets/staging-tuf/13.snapshot.json | 22 +++ test/assets/staging-tuf/13.targets.json | 151 ++++++++++++++++++ .../staging-tuf/2.registry.npmjs.org.json | 23 --- test/assets/staging-tuf/4.root.json | 65 -------- test/assets/staging-tuf/4.snapshot.json | 32 ---- test/assets/staging-tuf/4.targets.json | 135 ---------------- ...cb05900cb749235186c3bf9522d6d7ce.rekor.pub | 4 - ...ff9fa7fa87c6e23484fc1e0cec.ctfe_2022_2.pub | 4 - ...1def4e816c6c60cee69d421.trusted_root.json} | 29 ++-- ...d9b064d5cb60b4.fulcio_intermediate.crt.pem | 14 -- ...c19a78586de6ecfbfd8f289f5423.ctfe_2022.pub | 4 - ...dcc2b046cb173f51af659911fcd3.ctfe_2022.pub | 4 - ...cff1888e51ebd73924c12495.trusted_root.json | 112 ------------- ...a4ddf8f1968caa15255de8e37035af43a.ctfe.pub | 13 -- ...d21510da56d466ba5018401959cd66037.ctfe.pub | 13 -- ...b0614a46a86006969f8a7b84532.fulcio.crt.pem | 13 -- ...b70371e0d0802abe2.signing_config.v0.2.json | 45 ++++++ ...8f8df61bc7274189122c123446248426.keys.json | 26 --- ...2551fcaa870a30d4601ba1caf6f63699.keys.json | 26 --- test/assets/staging-tuf/timestamp.json | 39 ++--- test/unit/internal/test_trust.py | 34 ++-- test/unit/test_store.py | 16 +- 32 files changed, 474 insertions(+), 654 deletions(-) create mode 100644 sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/root.json create mode 100644 sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/signing_config.v0.2.json rename sigstore/_store/{staging => https%3A%2F%2Ftuf-repo-cdn.sigstage.dev}/trusted_root.json (61%) rename sigstore/_store/{prod => https%3A%2F%2Ftuf-repo-cdn.sigstore.dev}/root.json (100%) rename sigstore/_store/{prod => https%3A%2F%2Ftuf-repo-cdn.sigstore.dev}/signing_config.v0.2.json (86%) rename sigstore/_store/{prod => https%3A%2F%2Ftuf-repo-cdn.sigstore.dev}/trusted_root.json (100%) delete mode 100644 sigstore/_store/staging/root.json create mode 100644 test/assets/staging-tuf/13.snapshot.json create mode 100644 test/assets/staging-tuf/13.targets.json delete mode 100644 test/assets/staging-tuf/2.registry.npmjs.org.json delete mode 100644 test/assets/staging-tuf/4.root.json delete mode 100644 test/assets/staging-tuf/4.snapshot.json delete mode 100644 test/assets/staging-tuf/4.targets.json delete mode 100644 test/assets/staging-tuf/targets/09ab08698a67354a95d3b8897d9ce7eaef05f06f5ed5f0202d79c228579858ecc5816b7e1b7cc6786abe7d6aaa758e1fcb05900cb749235186c3bf9522d6d7ce.rekor.pub delete mode 100644 test/assets/staging-tuf/targets/3d035f94e1b14ac84627a28afdbed9a34861fb84239f76d73aa1a99f52262bfd95c4fa0ee71f1fd7e3bfb998d89cd5e0f0eafcff9fa7fa87c6e23484fc1e0cec.ctfe_2022_2.pub rename test/assets/staging-tuf/targets/{99f4f7728a889fa7db2fec893c387714a64aaf032fbe3035909fc8445effb857.trusted_root.json => 3f8ab41b9311910106caf66cb5e4117b1bee0d1871def4e816c6c60cee69d421.trusted_root.json} (61%) delete mode 100644 test/assets/staging-tuf/targets/90659875a02f73d1026055427c6d857c556e410e23748ff88aeb493227610fd2f5fbdd95ef2a21565f91438dfb3e073f50c4c9dd06f9a601b5d9b064d5cb60b4.fulcio_intermediate.crt.pem delete mode 100644 test/assets/staging-tuf/targets/910d899c7763563095a0fe684c8477573fedc19a78586de6ecfbfd8f289f5423.ctfe_2022.pub delete mode 100644 test/assets/staging-tuf/targets/ab975a75600fc366a837536d0dcba841b755552d21bb114498ff8ac9d2403f76643f5b91269bce5d124a365514719a3edee9dcc2b046cb173f51af659911fcd3.ctfe_2022.pub delete mode 100644 test/assets/staging-tuf/targets/acf0438a71de70bbf1813c908545281e0c4a1e3aafa2ce36b82c1cc24a9cce5169e9dcfe85c31bb4f662e94fdd9a686fa54fbbfccff1888e51ebd73924c12495.trusted_root.json delete mode 100644 test/assets/staging-tuf/targets/b861189e48df51186a39612230fba6b02af951f7b35ad9375e8ca182d0e085d470e26d69f7cd4d7450a0f223991e8e5a4ddf8f1968caa15255de8e37035af43a.ctfe.pub delete mode 100644 test/assets/staging-tuf/targets/bd7a6812a1f239dfddbbb19d36c7423d21510da56d466ba5018401959cd66037.ctfe.pub delete mode 100644 test/assets/staging-tuf/targets/c69ae618883a0c89c282c0943a1ad0c16b0a7788f74e47a1adefc631dac48a0c4449d8c3de7455ae7d772e43c4a87e341f180b0614a46a86006969f8a7b84532.fulcio.crt.pem create mode 100644 test/assets/staging-tuf/targets/cb9a48c332a0d515db7760ad6972a09a0f4ed721fe5e839b70371e0d0802abe2.signing_config.v0.2.json delete mode 100644 test/assets/staging-tuf/targets/registry.npmjs.org/7a8ec9678ad824cdccaa7a6dc0961caf8f8df61bc7274189122c123446248426.keys.json delete mode 100644 test/assets/staging-tuf/targets/registry.npmjs.org/881a853ee92d8cf513b07c164fea36b22a7305c256125bdfffdc5c65a4205c4c3fc2b5bcc98964349167ea68d40b8cd02551fcaa870a30d4601ba1caf6f63699.keys.json diff --git a/sigstore/_internal/trust.py b/sigstore/_internal/trust.py index d881d45f6..a528f6bab 100644 --- a/sigstore/_internal/trust.py +++ b/sigstore/_internal/trust.py @@ -568,7 +568,7 @@ def from_tuf( except TUFError as e: # TUF repo may not have signing config yet: hard code values for prod: if url == DEFAULT_TUF_URL: - embedded = read_embedded("signing_config.v0.2.json", "prod") + embedded = read_embedded("signing_config.v0.2.json", url) inner_sc = _SigningConfig().from_json(embedded) else: raise e diff --git a/sigstore/_internal/tuf.py b/sigstore/_internal/tuf.py index 115f44b54..c38becb61 100644 --- a/sigstore/_internal/tuf.py +++ b/sigstore/_internal/tuf.py @@ -29,7 +29,7 @@ from sigstore import __version__ from sigstore._utils import read_embedded -from sigstore.errors import RootError, TUFError +from sigstore.errors import TUFError _logger = logging.getLogger(__name__) @@ -70,8 +70,9 @@ def __init__(self, url: str, offline: bool = False) -> None: """ Create a new `TrustUpdater`, pulling from the given `url`. - The URL is expected to match one of `sigstore-python`'s known TUF - roots, i.e. for the production or staging Sigstore TUF repos. + TrustUpdater expects that either embedded data contains + a root.json for this url or that local data has been initialized + already. If not `offline`, TrustUpdater will update the TUF metadata from the remote repository. @@ -79,25 +80,17 @@ def __init__(self, url: str, offline: bool = False) -> None: self._repo_url = url self._metadata_dir, self._targets_dir = _get_dirs(url) - rsrc_prefix: str - if self._repo_url == DEFAULT_TUF_URL: - rsrc_prefix = "prod" - elif self._repo_url == STAGING_TUF_URL: - rsrc_prefix = "staging" - else: - raise RootError - - # Initialize targets cache dir + # Populate targets cache so we don't have to download these versions self._targets_dir.mkdir(parents=True, exist_ok=True) - trusted_root_target = self._targets_dir / "trusted_root.json" - - if not trusted_root_target.exists(): - try: - trusted_root_json = read_embedded("trusted_root.json", rsrc_prefix) - except FileNotFoundError as e: - raise RootError from e - trusted_root_target.write_bytes(trusted_root_json) + for artifact in ["trusted_root.json", "signing_config.v0.2.json"]: + artifact_path = self._targets_dir / artifact + if not artifact_path.exists(): + try: + data = read_embedded(artifact, url) + artifact_path.write_bytes(data) + except FileNotFoundError: + pass # this is ok: e.g. signing_config is not in prod repository yet _logger.debug(f"TUF metadata: {self._metadata_dir}") _logger.debug(f"TUF targets cache: {self._targets_dir}") @@ -110,9 +103,12 @@ def __init__(self, url: str, offline: bool = False) -> None: else: # Initialize and update the toplevel TUF metadata try: - root_json = read_embedded("root.json", rsrc_prefix) - except FileNotFoundError as e: - raise RootError from e + root_json = read_embedded("root.json", url) + except FileNotFoundError: + # embedded root not found: we can still initialize _if_ the local metadata + # exists already + root_json = None + self._updater = Updater( metadata_dir=str(self._metadata_dir), metadata_base_url=self._repo_url, @@ -121,6 +117,7 @@ def __init__(self, url: str, offline: bool = False) -> None: config=UpdaterConfig(app_user_agent=f"sigstore-python/{__version__}"), bootstrap=root_json, ) + try: self._updater.refresh() except Exception as e: @@ -167,7 +164,7 @@ def get_signing_config_path(self) -> str: TUFExceptions.DownloadError, TUFExceptions.RepositoryError, ) as e: - raise TUFError("Failed to download trusted key bundle") from e + raise TUFError("Failed to download signing config") from e _logger.debug("Found and verified signing config") return path diff --git a/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/root.json b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/root.json new file mode 100644 index 000000000..9206f75be --- /dev/null +++ b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/root.json @@ -0,0 +1,107 @@ +{ + "signatures": [ + { + "keyid": "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81", + "sig": "3044022064ac6af7f922e3bc8ac095d1fb59c5e65b52c8b378d3777b9223fc63b65c1f05022022a3722f464b3cfb985cdd76b76790533c5ac81613dade8f3a1136d4473dc466" + }, + { + "keyid": "61f9609d2655b346fcebccd66b509d5828168d5e447110e261f0bcc8553624bc", + "sig": "3046022100ef742d08c803a87e4eabbefbad528e40bdbe7aa9dcdcdcc024aa256315c8bcf202210089e444aebb431f743fad85cecbb16a3cfd62b624dbd37a9bfdce21135659bd8b" + }, + { + "keyid": "9471fbda95411d10109e467ad526082d15f14a38de54ea2ada9687ab39d8e237", + "sig": "" + }, + { + "keyid": "0374a9e18a20a2103736cb4277e2fdd7f8453642c7d9eaf4ad8aee9cf2d47bb5", + "sig": "" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": true, + "expires": "2025-08-01T13:24:50Z", + "keys": { + "0374a9e18a20a2103736cb4277e2fdd7f8453642c7d9eaf4ad8aee9cf2d47bb5": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoxkvDOmtGEknB3M+ZkPts8joDM0X\nIH5JZwPlgC2CXs/eqOuNF8AcEWwGYRiDhV/IMlQw5bg8PLICQcgsbrDiKg==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@mnm678" + }, + "61f9609d2655b346fcebccd66b509d5828168d5e447110e261f0bcc8553624bc": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE++Wv+DcLRk+mfkmlpCwl1GUi9EMh\npBUTz8K0fH7bE4mQuViGSyWA/eyMc0HvzZi6Xr0diHw0/lUPBvok214YQw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@kommendorkapten" + }, + "9471fbda95411d10109e467ad526082d15f14a38de54ea2ada9687ab39d8e237": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFHDb85JH+JYR1LQmxiz4UMokVMnP\nxKoWpaEnFCKXH8W4Fc/DfIxMnkpjCuvWUBdJXkO0aDIxwsij8TOFh2R7dw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@joshuagl" + }, + "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEohqIdE+yTl4OxpX8ZxNUPrg3SL9H\nBDnhZuceKkxy2oMhUOxhWweZeG3bfM1T4ZLnJimC6CAYVU5+F5jZCoftRw==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-keyowner": "@jku" + }, + "c3479007e861445ce5dc109d9661ed77b35bbc0e3f161852c46114266fc2daa4": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExxmEtmhF5U+i+v/6he4BcSLzCgMx\n/0qSrvDg6bUWwUrkSKS2vDpcJrhGy5fmmhRrGawjPp1ALpC3y1kqFTpXDg==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-online-uri": "gcpkms:projects/projectsigstore-staging/locations/global/keyRings/tuf-keyring/cryptoKeys/tuf-key/cryptoKeyVersions/2" + } + }, + "roles": { + "root": { + "keyids": [ + "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81", + "61f9609d2655b346fcebccd66b509d5828168d5e447110e261f0bcc8553624bc", + "9471fbda95411d10109e467ad526082d15f14a38de54ea2ada9687ab39d8e237", + "0374a9e18a20a2103736cb4277e2fdd7f8453642c7d9eaf4ad8aee9cf2d47bb5" + ], + "threshold": 2 + }, + "snapshot": { + "keyids": [ + "c3479007e861445ce5dc109d9661ed77b35bbc0e3f161852c46114266fc2daa4" + ], + "threshold": 1, + "x-tuf-on-ci-expiry-period": 3650, + "x-tuf-on-ci-signing-period": 365 + }, + "targets": { + "keyids": [ + "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81", + "61f9609d2655b346fcebccd66b509d5828168d5e447110e261f0bcc8553624bc", + "9471fbda95411d10109e467ad526082d15f14a38de54ea2ada9687ab39d8e237", + "0374a9e18a20a2103736cb4277e2fdd7f8453642c7d9eaf4ad8aee9cf2d47bb5" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "c3479007e861445ce5dc109d9661ed77b35bbc0e3f161852c46114266fc2daa4" + ], + "threshold": 1, + "x-tuf-on-ci-expiry-period": 7, + "x-tuf-on-ci-signing-period": 6 + } + }, + "spec_version": "1.0", + "version": 11, + "x-tuf-on-ci-expiry-period": 182, + "x-tuf-on-ci-signing-period": 35 + } +} \ No newline at end of file diff --git a/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/signing_config.v0.2.json b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/signing_config.v0.2.json new file mode 100644 index 000000000..fe66ad97b --- /dev/null +++ b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/signing_config.v0.2.json @@ -0,0 +1,45 @@ +{ + "mediaType": "application/vnd.dev.sigstore.signingconfig.v0.2+json", + "caUrls": [ + { + "url": "https://fulcio.sigstage.dev", + "majorApiVersion": 1, + "validFor": { + "start": "2022-04-14T21:38:40Z" + } + } + ], + "oidcUrls": [ + { + "url": "https://oauth2.sigstage.dev/auth", + "majorApiVersion": 1, + "validFor": { + "start": "2025-04-16T00:00:00Z" + } + } + ], + "rekorTlogUrls": [ + { + "url": "https://rekor.sigstage.dev", + "majorApiVersion": 1, + "validFor": { + "start": "2021-01-12T11:53:27Z" + } + } + ], + "tsaUrls": [ + { + "url": "https://timestamp.sigstage.dev/api/v1/timestamp", + "majorApiVersion": 1, + "validFor": { + "start": "2025-04-09T00:00:00Z" + } + } + ], + "rekorTlogConfig": { + "selector": "ANY" + }, + "tsaConfig": { + "selector": "ANY" + } +} \ No newline at end of file diff --git a/sigstore/_store/staging/trusted_root.json b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/trusted_root.json similarity index 61% rename from sigstore/_store/staging/trusted_root.json rename to sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/trusted_root.json index f5b8853e7..8691ef5d3 100644 --- a/sigstore/_store/staging/trusted_root.json +++ b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstage.dev/trusted_root.json @@ -8,7 +8,7 @@ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDODRU688UYGuy54mNUlaEBiQdTE9nYLr0lg6RXowI/QV/RE1azBn4Eg5/2uTOMbhB1/gfcHzijzFi9Tk+g1Prg==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { - "start": "2021-01-12T11:53:27.000Z" + "start": "2021-01-12T11:53:27Z" } }, "logId": { @@ -34,7 +34,7 @@ ] }, "validFor": { - "start": "2022-04-14T21:38:40.000Z" + "start": "2022-04-14T21:38:40Z" } } ], @@ -46,8 +46,8 @@ "rawBytes": "MIICCgKCAgEA27A2MPQXm0I0v7/Ly5BIauDjRZF5Jor9vU+QheoE2UIIsZHcyYq3slHzSSHy2lLj1ZD2d91CtJ492ZXqnBmsr4TwZ9jQ05tW2mGIRI8u2DqN8LpuNYZGz/f9SZrjhQQmUttqWmtu3UoLfKz6NbNXUnoo+NhZFcFRLXJ8VporVhuiAmL7zqT53cXR3yQfFPCUDeGnRksnlhVIAJc3AHZZSHQJ8DEXMhh35TVv2nYhTI3rID7GwjXXw4ocz7RGDD37ky6p39Tl5NB71gT1eSqhZhGHEYHIPXraEBd5+3w9qIuLWlp5Ej/K6Mu4ELioXKCUimCbwy+Cs8UhHFlqcyg4AysOHJwIadXIa8LsY51jnVSGrGOEBZevopmQPNPtyfFY3dmXSS+6Z3RD2Gd6oDnNGJzpSyEk410Ag5uvNDfYzJLCWX9tU8lIxNwdFYmIwpd89HijyRyoGnoJ3entd63cvKfuuix5r+GHyKp1Xm1L5j5AWM6P+z0xigwkiXnt+adexAl1J9wdDxv/pUFEESRF4DG8DFGVtbdH6aR1A5/vD4krO4tC1QYUSeyL5Mvsw8WRqIFHcXtgybtxylljvNcGMV1KXQC8UFDmpGZVDSHx6v3e/BHMrZ7gjoCCfVMZ/cFcQi0W2AIHPYEMH/C95J2r4XbHMRdYXpovpOoT5Ca78gsCAwEAAQ==", "keyDetails": "PKCS1_RSA_PKCS1V5", "validFor": { - "start": "2021-03-14T00:00:00.000Z", - "end": "2022-07-31T00:00:00.000Z" + "start": "2021-03-14T00:00:00Z", + "end": "2022-07-31T00:00:00Z" } }, "logId": { @@ -61,8 +61,8 @@ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEh99xuRi6slBFd8VUJoK/rLigy4bYeSYWO/fE6Br7r0D8NpMI94+A63LR/WvLxpUUGBpY8IJA3iU2telag5CRpA==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { - "start": "2022-07-01T00:00:00.000Z", - "end": "2022-07-31T00:00:00.000Z" + "start": "2022-07-01T00:00:00Z", + "end": "2022-07-31T00:00:00Z" } }, "logId": { @@ -76,7 +76,7 @@ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8gEDKNme8AnXuPBgHjrtXdS6miHqc24CRblNEOFpiJRngeq8Ko73Y+K18yRYVf1DXD4AVLwvKyzdNdl5n0jUSQ==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { - "start": "2022-07-01T00:00:00.000Z" + "start": "2022-07-01T00:00:00Z" } }, "logId": { @@ -87,25 +87,22 @@ "timestampAuthorities": [ { "subject": { - "organization": "GitHub, Inc.", - "commonName": "Internal Services Root - staging" + "organization": "sigstore.dev", + "commonName": "sigstore-tsa-selfsigned" }, - "uri": "tsa.github.internal", + "uri": "https://timestamp.sigstage.dev/api/v1/timestamp", "certChain": { "certificates": [ { - "rawBytes": "MIICEzCCAZigAwIBAgIUMpRykCcZaSOBipYce6r2DlnM7vUwCgYIKoZIzj0EAwMwPDEVMBMGA1UEChMMR2l0SHViLCBJbmMuMSMwIQYDVQQDExpUU0EgaW50ZXJtZWRpYXRlIC0gc3RhZ2luZzAeFw0yMzA2MTQxMjAwMDBaFw0yNDA2MTMxMjAwMDBaMDwxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEjMCEGA1UEAxMaVFNBIFRpbWVzdGFtcGluZyAtIHN0YWdpbmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATWAMg1BEHAzb03PHUKJiRJZdXcKIL0K/ks3Ylq5F5YDRIxUN4o8yeIaCWXa6i16zi8nXMFsa+3XrYM8mUyi9F6o3gwdjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUr+RZdcTNo31p3FuR0pajelcnr40wHwYDVR0jBBgwFoAUCmpQzrB6hAnlizGx37LrhKEzsT4wFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwCgYIKoZIzj0EAwMDaQAwZgIxAIPUlZB2/p5rpCM3HCn1R8G5TIIW6aZPKtfPWDkNQY0bpFu6e8Dkm2TV3jfgYExuBgIxAOA+vTlDDJoz/qTMMs8VSpw3AMgktlMEhd8V0E+aLW5OizfphuiidkqkqkbCwRSW1w==" - }, - { - "rawBytes": "MIICNzCCAb6gAwIBAgIUUXRsBKgGXjrJbdJCQPJMsjfyJcYwCgYIKoZIzj0EAwMwQjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMSkwJwYDVQQDEyBJbnRlcm5hbCBTZXJ2aWNlcyBSb290IC0gc3RhZ2luZzAeFw0yMzA2MTQwMDAwMDBaFw0yODA2MTIwMDAwMDBaMDwxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEjMCEGA1UEAxMaVFNBIGludGVybWVkaWF0ZSAtIHN0YWdpbmcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAS/upihrvu/9+w1Ybfog3B1a8KfQa1bn7DLcJz2iumo+oCfg2bcbyRWygu8zRmrzJKp4HgQHC4LZJEEWm/MNIN1o6wVVmiDTZw01tk4aInmRVF13VKMscdzW5Ho4sYaeOejezB5MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDCDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQKalDOsHqECeWLMbHfsuuEoTOxPjAfBgNVHSMEGDAWgBR04GYtT79vaQmAEPPEte8q+W1KRTAKBggqhkjOPQQDAwNnADBkAjBOTWZP1QYnmHpFqL73eSzhmSLiHs9pXsQghK0p8pvlAg0R9bxAyXGIZ8qx+k2iIGcCMDRQIScz0gu2Xef3++p2vFYouBsIKbqxv0raJuIlmGiYEvb22MDpAitevKAgqNVMEg==" + "rawBytes": "MIICDzCCAZagAwIBAgIUCjWhBmHV4kFzxomWp/J98n4DfKcwCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTAzMjgwOTE0MDZaFw0zNTAzMjYwODE0MDZaMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEx1v5F3HpD9egHuknpBFlRz7QBRDJu4aeVzt9zJLRY0lvmx1lF7WBM2c9AN8ZGPQsmDqHlJN2R/7+RxLkvlLzkc19IOx38t7mGGEcB7agUDdCF/Ky3RTLSK0Xo/0AgHQdo2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFKj8ZPYo3i7mO3NPVIxSxOGc3VOlMB8GA1UdIwQYMBaAFDsgRlletTJNRzDObmPuc3RH8gR9MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMDA2cAMGQCMESvVS6GGtF33+J19TfwENWJXjRv4i0/HQFwLUSkX6TfV7g0nG8VnqNHJLvEpAtOjQIwUD3uywTXorQP1DgbV09rF9Yen+CEqs/iEpieJWPst280SSOZ5Na+dyPVk9/8SFk6" }, { - "rawBytes": "MIICCDCCAY6gAwIBAgIULHHP/UhbXJbdyZfT6gHgTzIYF4EwCgYIKoZIzj0EAwMwQjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMSkwJwYDVQQDEyBJbnRlcm5hbCBTZXJ2aWNlcyBSb290IC0gc3RhZ2luZzAeFw0yMzA2MTQwMDAwMDBaFw0zMzA2MTEwMDAwMDBaMEIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEpMCcGA1UEAxMgSW50ZXJuYWwgU2VydmljZXMgUm9vdCAtIHN0YWdpbmcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASocByKBUdzgtqRXcpe/AE5oPoDMWTQqz1/jUQOA8qoEjYBXg9gfGU5KHK/UdwQc4lxbZEA9nJS9vUQAMVV5Es9B4thNHThKR4hFmCL8kKIEoMzXx282Qr6x4ZHYk4tQsCjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBR04GYtT79vaQmAEPPEte8q+W1KRTAKBggqhkjOPQQDAwNoADBlAjBBOu3RtlH1FLvfHPhyoWJHgm+PSNrsWQLRkmWQgAfNPYsfO5fWyhAebMV3FpKVPBICMQCVaie4NAsGi+AHLDhGnPn4Qptz0LBH2So6AVJS24ICeDUDQxKeUTNkUsy6Qgg97/4=" + "rawBytes": "MIIB9zCCAXygAwIBAgIUCPExEFKiQh0dP4sp5ltmSYSSkFUwCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTAzMjgwOTE0MDZaFw0zNTAzMjYwODE0MDZaMDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATt0tIDWyo4ARfL9BaSo0W5bJQEbKJTU/u7llvdjSI5aTkOAJa8tixn2+LEfPG4dMFdsMPtsIuU1qn2OqFiuMk6vHv/c+az25RQVY1oo50iMb0jIL3N4FgwhPFpZnCbQPOjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQ7IEZZXrUyTUcwzm5j7nN0R/IEfTAKBggqhkjOPQQDAwNpADBmAjEA2MI1VXgbf3dUOSc95hSRypBKOab18eh2xzQtxUsHvWeY+1iFgyMluUuNR6taoSmFAjEA31m2czguZhKYX+4JSKu5pRYhBTXAd8KKQ3xdPRX/qCaLvT2qJAEQ1YQM3EJRrtI7" } ] }, "validFor": { - "start": "2023-06-15T00:00:00Z" + "start": "2025-04-09T00:00:00Z" } } ] diff --git a/sigstore/_store/prod/root.json b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/root.json similarity index 100% rename from sigstore/_store/prod/root.json rename to sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/root.json diff --git a/sigstore/_store/prod/signing_config.v0.2.json b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/signing_config.v0.2.json similarity index 86% rename from sigstore/_store/prod/signing_config.v0.2.json rename to sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/signing_config.v0.2.json index dc4ae078b..5a7b47cfb 100644 --- a/sigstore/_store/prod/signing_config.v0.2.json +++ b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/signing_config.v0.2.json @@ -1,4 +1,5 @@ { + "comment": "Place holder for use until prod actually has a signing config: see ClientTrustConfig.from_tuf()", "mediaType": "application/vnd.dev.sigstore.signingconfig.v0.2+json", "caUrls": [ { diff --git a/sigstore/_store/prod/trusted_root.json b/sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/trusted_root.json similarity index 100% rename from sigstore/_store/prod/trusted_root.json rename to sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/trusted_root.json diff --git a/sigstore/_store/staging/root.json b/sigstore/_store/staging/root.json deleted file mode 100644 index e506177b8..000000000 --- a/sigstore/_store/staging/root.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "signed": { - "_type": "root", - "spec_version": "1.0", - "version": 4, - "expires": "2029-03-05T22:50:21Z", - "keys": { - "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXMZ7rD8tWDE4lK/+naJN7INMxNC7\nbMMANDqTQE7WpzyzffWOg59hc/MwbvJtvuxhO9mEu3GD3Cn0HffFlmVRiA==\n-----END PUBLIC KEY-----\n" - } - }, - "c8e09a68b5821b75462ae0df52151c81deb7f1838246dc1da8c34cc91ec12bda": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEL3vL/VeaH6nBbo4rekyO4cc/QthS\n+nlyJXCXSnyIMAtLmVTa8Pf0qG6YIVaR0TmLkyk9YoSVsZakxuMTuaEwrg==\n-----END PUBLIC KEY-----\n" - } - } - }, - "roles": { - "root": { - "keyids": [ - "c8e09a68b5821b75462ae0df52151c81deb7f1838246dc1da8c34cc91ec12bda" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "c8e09a68b5821b75462ae0df52151c81deb7f1838246dc1da8c34cc91ec12bda" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600" - ], - "threshold": 1 - } - }, - "consistent_snapshot": true - }, - "signatures": [ - { - "keyid": "c8e09a68b5821b75462ae0df52151c81deb7f1838246dc1da8c34cc91ec12bda", - "sig": "3044022006fe8fff51d18753aeff141f81a962b8ac33f49831bbbec1334b2733ea96890002206e6f343c9c7b98a2ebd1f0b51aa5286ed3a4d48e271c77d88ea77499231bff5c" - } - ] -} \ No newline at end of file diff --git a/sigstore/_utils.py b/sigstore/_utils.py index 906c77213..4a104e986 100644 --- a/sigstore/_utils.py +++ b/sigstore/_utils.py @@ -22,6 +22,7 @@ import hashlib import sys from typing import IO, NewType, Union +from urllib import parse from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ec, rsa @@ -195,12 +196,13 @@ def _sha256_streaming(io: IO[bytes]) -> bytes: return sha256.digest() -def read_embedded(name: str, prefix: str) -> bytes: +def read_embedded(name: str, url: str) -> bytes: """ - Read a resource embedded in this distribution of sigstore-python, - returning its contents as bytes. + Read a resource for a given TUF repository embedded in this distribution + of sigstore-python, returning its contents as bytes. """ - b: bytes = resources.files("sigstore._store").joinpath(prefix, name).read_bytes() + embed_dir = parse.quote(url, safe="") + b: bytes = resources.files("sigstore._store").joinpath(embed_dir, name).read_bytes() return b diff --git a/test/assets/staging-tuf/13.snapshot.json b/test/assets/staging-tuf/13.snapshot.json new file mode 100644 index 000000000..1eb631496 --- /dev/null +++ b/test/assets/staging-tuf/13.snapshot.json @@ -0,0 +1,22 @@ +{ + "signatures": [ + { + "keyid": "c3479007e861445ce5dc109d9661ed77b35bbc0e3f161852c46114266fc2daa4", + "sig": "3046022100c36bf62c4b5f72f8e3defc1af05148518a282394b304f0e0a154c10feeaee9a1022100ed8bb83508e1fcd3906bdf71af0da30f066a048db0f8da589db7dfe5f1458537" + } + ], + "signed": { + "_type": "snapshot", + "expires": "2035-04-30T07:17:48Z", + "meta": { + "registry.npmjs.org.json": { + "version": 5 + }, + "targets.json": { + "version": 13 + } + }, + "spec_version": "1.0", + "version": 13 + } +} \ No newline at end of file diff --git a/test/assets/staging-tuf/13.targets.json b/test/assets/staging-tuf/13.targets.json new file mode 100644 index 000000000..e95d33949 --- /dev/null +++ b/test/assets/staging-tuf/13.targets.json @@ -0,0 +1,151 @@ +{ + "signatures": [ + { + "keyid": "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81", + "sig": "3046022100c1968b55a40906590168f9b9ecd2251ef4056f79e9067fb80374ad4bc1a770a102210085d17acfcd779f8d004b54e0c5170e9e4629487603859bf85f4519d46ef3a994" + }, + { + "keyid": "61f9609d2655b346fcebccd66b509d5828168d5e447110e261f0bcc8553624bc", + "sig": "3046022100fc18a5d048d94be077f240866f344bc679098dde898f4d61ed44ba1cd37f86ec022100cc3b9d06b15ea56f953afbd3917a53c674b86e94ee5d3ffb160f3f465c2fee70" + }, + { + "keyid": "9471fbda95411d10109e467ad526082d15f14a38de54ea2ada9687ab39d8e237", + "sig": "" + }, + { + "keyid": "0374a9e18a20a2103736cb4277e2fdd7f8453642c7d9eaf4ad8aee9cf2d47bb5", + "sig": "" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "5e3a4021b11a425fd0a444f1670457ce5b15bbe036144f2417426f7f4b9721da": { + "keytype": "ecdsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVfei1dXQRVeArCMcTDgxJtYg+Fs7\nV87DjhQbGlRJPyC7SW5TbNNkmvpmi4LeTv6moLVZ7T2nVqiRZbSkD+cf8w==\n-----END PUBLIC KEY-----\n" + }, + "scheme": "ecdsa-sha2-nistp256", + "x-tuf-on-ci-online-uri": "azurekms://npm-tuf-delegate.vault.azure.net/keys/npm-tuf-delegate-2024-08/e2772c1d01ca400da571096889f1660e" + } + }, + "roles": [ + { + "keyids": [ + "5e3a4021b11a425fd0a444f1670457ce5b15bbe036144f2417426f7f4b9721da" + ], + "name": "registry.npmjs.org", + "paths": [ + "registry.npmjs.org/*" + ], + "terminating": true, + "threshold": 1 + } + ] + }, + "expires": "2035-04-27T13:57:15Z", + "spec_version": "1.0", + "targets": { + "ctfe.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://ctfe.sigstage.dev/test", + "usage": "CTFE" + } + }, + "hashes": { + "sha256": "bd7a6812a1f239dfddbbb19d36c7423d21510da56d466ba5018401959cd66037" + }, + "length": 775 + }, + "ctfe_2022.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://ctfe.sigstage.dev/2022", + "usage": "CTFE" + } + }, + "hashes": { + "sha256": "910d899c7763563095a0fe684c8477573fedc19a78586de6ecfbfd8f289f5423" + }, + "length": 178 + }, + "ctfe_2022_2.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://ctfe.sigstage.dev/2022-2", + "usage": "CTFE" + } + }, + "hashes": { + "sha256": "7054b4f15f969daca1c242bb9e77527abaf0b9acf9818a2a35144e4b32b20dc6" + }, + "length": 178 + }, + "fulcio.crt.pem": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://fulcio.sigstage.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "0e6b0442485ad552bea5f62f11c29e2acfda35307d7538430b4cc1dbef49bff1" + }, + "length": 741 + }, + "fulcio_intermediate.crt.pem": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://fulcio.sigstage.dev", + "usage": "Fulcio" + } + }, + "hashes": { + "sha256": "782868913fe13c385105ddf33e827191386f58da40a931f2075a7e27b1b6ac7b" + }, + "length": 790 + }, + "rekor.pub": { + "custom": { + "sigstore": { + "status": "Active", + "uri": "https://rekor.sigstage.dev", + "usage": "Rekor" + } + }, + "hashes": { + "sha256": "1d80b8f72505a43e65e6e125247cd508f61b459dc457c1d1bcb78d96e1760959" + }, + "length": 178 + }, + "signing_config.json": { + "hashes": { + "sha256": "bf52f4aa7dc05849a6c8c760f5ae2ea4047b03b59505d9280efe02a1ec63c6e8" + }, + "length": 220 + }, + "signing_config.v0.2.json": { + "hashes": { + "sha256": "cb9a48c332a0d515db7760ad6972a09a0f4ed721fe5e839b70371e0d0802abe2" + }, + "length": 885 + }, + "trusted_root.json": { + "hashes": { + "sha256": "3f8ab41b9311910106caf66cb5e4117b1bee0d1871def4e816c6c60cee69d421" + }, + "length": 6399 + } + }, + "version": 13, + "x-tuf-on-ci-expiry-period": 3650, + "x-tuf-on-ci-signing-period": 365 + } +} \ No newline at end of file diff --git a/test/assets/staging-tuf/2.registry.npmjs.org.json b/test/assets/staging-tuf/2.registry.npmjs.org.json deleted file mode 100644 index d53f15267..000000000 --- a/test/assets/staging-tuf/2.registry.npmjs.org.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "signed": { - "_type": "targets", - "spec_version": "1.0", - "version": 2, - "expires": "2028-09-29T21:10:55Z", - "targets": { - "registry.npmjs.org/keys.json": { - "length": 1017, - "hashes": { - "sha256": "7a8ec9678ad824cdccaa7a6dc0961caf8f8df61bc7274189122c123446248426", - "sha512": "881a853ee92d8cf513b07c164fea36b22a7305c256125bdfffdc5c65a4205c4c3fc2b5bcc98964349167ea68d40b8cd02551fcaa870a30d4601ba1caf6f63699" - } - } - } - }, - "signatures": [ - { - "keyid": "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600", - "sig": "3045022057b9fc8afd9feaf45cf3173d3420fdcd6b68c22e4ef7b47e80a6887e1f20246c0221009f39c42fac630ab354c5197288c9a82ab6d46a59b423f81fff719da57cff16ab" - } - ] -} \ No newline at end of file diff --git a/test/assets/staging-tuf/4.root.json b/test/assets/staging-tuf/4.root.json deleted file mode 100644 index e506177b8..000000000 --- a/test/assets/staging-tuf/4.root.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "signed": { - "_type": "root", - "spec_version": "1.0", - "version": 4, - "expires": "2029-03-05T22:50:21Z", - "keys": { - "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXMZ7rD8tWDE4lK/+naJN7INMxNC7\nbMMANDqTQE7WpzyzffWOg59hc/MwbvJtvuxhO9mEu3GD3Cn0HffFlmVRiA==\n-----END PUBLIC KEY-----\n" - } - }, - "c8e09a68b5821b75462ae0df52151c81deb7f1838246dc1da8c34cc91ec12bda": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEL3vL/VeaH6nBbo4rekyO4cc/QthS\n+nlyJXCXSnyIMAtLmVTa8Pf0qG6YIVaR0TmLkyk9YoSVsZakxuMTuaEwrg==\n-----END PUBLIC KEY-----\n" - } - } - }, - "roles": { - "root": { - "keyids": [ - "c8e09a68b5821b75462ae0df52151c81deb7f1838246dc1da8c34cc91ec12bda" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "c8e09a68b5821b75462ae0df52151c81deb7f1838246dc1da8c34cc91ec12bda" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600" - ], - "threshold": 1 - } - }, - "consistent_snapshot": true - }, - "signatures": [ - { - "keyid": "c8e09a68b5821b75462ae0df52151c81deb7f1838246dc1da8c34cc91ec12bda", - "sig": "3044022006fe8fff51d18753aeff141f81a962b8ac33f49831bbbec1334b2733ea96890002206e6f343c9c7b98a2ebd1f0b51aa5286ed3a4d48e271c77d88ea77499231bff5c" - } - ] -} \ No newline at end of file diff --git a/test/assets/staging-tuf/4.snapshot.json b/test/assets/staging-tuf/4.snapshot.json deleted file mode 100644 index 013e76b16..000000000 --- a/test/assets/staging-tuf/4.snapshot.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "signed": { - "_type": "snapshot", - "spec_version": "1.0", - "version": 4, - "expires": "2028-09-26T22:52:19Z", - "meta": { - "registry.npmjs.org.json": { - "length": 715, - "hashes": { - "sha256": "4dc55b2b468b0d1c9629c457c5cfce2cc1c330c59c5a7cf71cb7549f1ef76f1d", - "sha512": "278f4b6112db9d4bd9366e1717cf710ad7eacf44605fd4f894c3374fc5dff850a1a03c24c4a885d050a4ac1a86fa6929537fae12d8c2864c8e0c239b382d5556" - }, - "version": 2 - }, - "targets.json": { - "length": 4120, - "hashes": { - "sha256": "83107aa29ad45bf40c198d370b299272df612e5f03db2c06c7f90fca1fb1af5e", - "sha512": "b32a2ce40ec74aa453c34a6458a06abd5a0d28ded1114db9b8d49cb26eb6cce81790c9d019d5c9d88359ac78bddafe335225285485fa5443283351217da73e5d" - }, - "version": 4 - } - } - }, - "signatures": [ - { - "keyid": "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600", - "sig": "3046022100be9bafe7c1ce4efb9d39082a164eca2205103e701164512b6c9286909e4515e6022100caab046152056039b0e72a2246ce4e9af2576fff0c56272d76a9653bdb7e502e" - } - ] -} \ No newline at end of file diff --git a/test/assets/staging-tuf/4.targets.json b/test/assets/staging-tuf/4.targets.json deleted file mode 100644 index 7aec6c837..000000000 --- a/test/assets/staging-tuf/4.targets.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "signed": { - "_type": "targets", - "spec_version": "1.0", - "version": 4, - "expires": "2029-03-05T22:50:21Z", - "targets": { - "ctfe.pub": { - "length": 775, - "hashes": { - "sha256": "bd7a6812a1f239dfddbbb19d36c7423d21510da56d466ba5018401959cd66037", - "sha512": "b861189e48df51186a39612230fba6b02af951f7b35ad9375e8ca182d0e085d470e26d69f7cd4d7450a0f223991e8e5a4ddf8f1968caa15255de8e37035af43a" - }, - "custom": { - "sigstore": { - "status": "Active", - "uri": "https://ctfe.sigstage.dev/test", - "usage": "CTFE" - } - } - }, - "ctfe_2022.pub": { - "length": 178, - "hashes": { - "sha256": "910d899c7763563095a0fe684c8477573fedc19a78586de6ecfbfd8f289f5423", - "sha512": "ab975a75600fc366a837536d0dcba841b755552d21bb114498ff8ac9d2403f76643f5b91269bce5d124a365514719a3edee9dcc2b046cb173f51af659911fcd3" - }, - "custom": { - "sigstore": { - "status": "Active", - "uri": "https://ctfe.sigstage.dev/2022", - "usage": "CTFE" - } - } - }, - "ctfe_2022_2.pub": { - "length": 178, - "hashes": { - "sha256": "7054b4f15f969daca1c242bb9e77527abaf0b9acf9818a2a35144e4b32b20dc6", - "sha512": "3d035f94e1b14ac84627a28afdbed9a34861fb84239f76d73aa1a99f52262bfd95c4fa0ee71f1fd7e3bfb998d89cd5e0f0eafcff9fa7fa87c6e23484fc1e0cec" - }, - "custom": { - "sigstore": { - "status": "Active", - "uri": "https://ctfe.sigstage.dev/2022-2", - "usage": "CTFE" - } - } - }, - "fulcio.crt.pem": { - "length": 741, - "hashes": { - "sha256": "0e6b0442485ad552bea5f62f11c29e2acfda35307d7538430b4cc1dbef49bff1", - "sha512": "c69ae618883a0c89c282c0943a1ad0c16b0a7788f74e47a1adefc631dac48a0c4449d8c3de7455ae7d772e43c4a87e341f180b0614a46a86006969f8a7b84532" - }, - "custom": { - "sigstore": { - "status": "Active", - "uri": "https://fulcio.sigstage.dev", - "usage": "Fulcio" - } - } - }, - "fulcio_intermediate.crt.pem": { - "length": 790, - "hashes": { - "sha256": "782868913fe13c385105ddf33e827191386f58da40a931f2075a7e27b1b6ac7b", - "sha512": "90659875a02f73d1026055427c6d857c556e410e23748ff88aeb493227610fd2f5fbdd95ef2a21565f91438dfb3e073f50c4c9dd06f9a601b5d9b064d5cb60b4" - }, - "custom": { - "sigstore": { - "status": "Active", - "uri": "https://fulcio.sigstage.dev", - "usage": "Fulcio" - } - } - }, - "rekor.pub": { - "length": 178, - "hashes": { - "sha256": "1d80b8f72505a43e65e6e125247cd508f61b459dc457c1d1bcb78d96e1760959", - "sha512": "09ab08698a67354a95d3b8897d9ce7eaef05f06f5ed5f0202d79c228579858ecc5816b7e1b7cc6786abe7d6aaa758e1fcb05900cb749235186c3bf9522d6d7ce" - }, - "custom": { - "sigstore": { - "status": "Active", - "uri": "https://rekor.sigstage.dev", - "usage": "Rekor" - } - } - }, - "trusted_root.json": { - "length": 7256, - "hashes": { - "sha256": "99f4f7728a889fa7db2fec893c387714a64aaf032fbe3035909fc8445effb857", - "sha512": "acf0438a71de70bbf1813c908545281e0c4a1e3aafa2ce36b82c1cc24a9cce5169e9dcfe85c31bb4f662e94fdd9a686fa54fbbfccff1888e51ebd73924c12495" - } - } - }, - "delegations": { - "keys": { - "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600": { - "keytype": "ecdsa-sha2-nistp256", - "scheme": "ecdsa-sha2-nistp256", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXMZ7rD8tWDE4lK/+naJN7INMxNC7\nbMMANDqTQE7WpzyzffWOg59hc/MwbvJtvuxhO9mEu3GD3Cn0HffFlmVRiA==\n-----END PUBLIC KEY-----\n" - } - } - }, - "roles": [ - { - "name": "registry.npmjs.org", - "keyids": [ - "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600" - ], - "threshold": 1, - "terminating": true, - "paths": [ - "registry.npmjs.org/*" - ] - } - ] - } - }, - "signatures": [ - { - "keyid": "c8e09a68b5821b75462ae0df52151c81deb7f1838246dc1da8c34cc91ec12bda", - "sig": "3045022100f96ad83711dcf8766cea141c0726c48ebdd982116eb5e8a29447ae956d93cc050220315ac2124fb8a66e2bbea4810bd857da8ba1abca1360f9b287d16647bdfcd066" - } - ] -} \ No newline at end of file diff --git a/test/assets/staging-tuf/targets/09ab08698a67354a95d3b8897d9ce7eaef05f06f5ed5f0202d79c228579858ecc5816b7e1b7cc6786abe7d6aaa758e1fcb05900cb749235186c3bf9522d6d7ce.rekor.pub b/test/assets/staging-tuf/targets/09ab08698a67354a95d3b8897d9ce7eaef05f06f5ed5f0202d79c228579858ecc5816b7e1b7cc6786abe7d6aaa758e1fcb05900cb749235186c3bf9522d6d7ce.rekor.pub deleted file mode 100644 index 4234e16c3..000000000 --- a/test/assets/staging-tuf/targets/09ab08698a67354a95d3b8897d9ce7eaef05f06f5ed5f0202d79c228579858ecc5816b7e1b7cc6786abe7d6aaa758e1fcb05900cb749235186c3bf9522d6d7ce.rekor.pub +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDODRU688UYGuy54mNUlaEBiQdTE9 -nYLr0lg6RXowI/QV/RE1azBn4Eg5/2uTOMbhB1/gfcHzijzFi9Tk+g1Prg== ------END PUBLIC KEY----- diff --git a/test/assets/staging-tuf/targets/3d035f94e1b14ac84627a28afdbed9a34861fb84239f76d73aa1a99f52262bfd95c4fa0ee71f1fd7e3bfb998d89cd5e0f0eafcff9fa7fa87c6e23484fc1e0cec.ctfe_2022_2.pub b/test/assets/staging-tuf/targets/3d035f94e1b14ac84627a28afdbed9a34861fb84239f76d73aa1a99f52262bfd95c4fa0ee71f1fd7e3bfb998d89cd5e0f0eafcff9fa7fa87c6e23484fc1e0cec.ctfe_2022_2.pub deleted file mode 100644 index 0f5eb8637..000000000 --- a/test/assets/staging-tuf/targets/3d035f94e1b14ac84627a28afdbed9a34861fb84239f76d73aa1a99f52262bfd95c4fa0ee71f1fd7e3bfb998d89cd5e0f0eafcff9fa7fa87c6e23484fc1e0cec.ctfe_2022_2.pub +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8gEDKNme8AnXuPBgHjrtXdS6miHq -c24CRblNEOFpiJRngeq8Ko73Y+K18yRYVf1DXD4AVLwvKyzdNdl5n0jUSQ== ------END PUBLIC KEY----- diff --git a/test/assets/staging-tuf/targets/99f4f7728a889fa7db2fec893c387714a64aaf032fbe3035909fc8445effb857.trusted_root.json b/test/assets/staging-tuf/targets/3f8ab41b9311910106caf66cb5e4117b1bee0d1871def4e816c6c60cee69d421.trusted_root.json similarity index 61% rename from test/assets/staging-tuf/targets/99f4f7728a889fa7db2fec893c387714a64aaf032fbe3035909fc8445effb857.trusted_root.json rename to test/assets/staging-tuf/targets/3f8ab41b9311910106caf66cb5e4117b1bee0d1871def4e816c6c60cee69d421.trusted_root.json index f5b8853e7..8691ef5d3 100644 --- a/test/assets/staging-tuf/targets/99f4f7728a889fa7db2fec893c387714a64aaf032fbe3035909fc8445effb857.trusted_root.json +++ b/test/assets/staging-tuf/targets/3f8ab41b9311910106caf66cb5e4117b1bee0d1871def4e816c6c60cee69d421.trusted_root.json @@ -8,7 +8,7 @@ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDODRU688UYGuy54mNUlaEBiQdTE9nYLr0lg6RXowI/QV/RE1azBn4Eg5/2uTOMbhB1/gfcHzijzFi9Tk+g1Prg==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { - "start": "2021-01-12T11:53:27.000Z" + "start": "2021-01-12T11:53:27Z" } }, "logId": { @@ -34,7 +34,7 @@ ] }, "validFor": { - "start": "2022-04-14T21:38:40.000Z" + "start": "2022-04-14T21:38:40Z" } } ], @@ -46,8 +46,8 @@ "rawBytes": "MIICCgKCAgEA27A2MPQXm0I0v7/Ly5BIauDjRZF5Jor9vU+QheoE2UIIsZHcyYq3slHzSSHy2lLj1ZD2d91CtJ492ZXqnBmsr4TwZ9jQ05tW2mGIRI8u2DqN8LpuNYZGz/f9SZrjhQQmUttqWmtu3UoLfKz6NbNXUnoo+NhZFcFRLXJ8VporVhuiAmL7zqT53cXR3yQfFPCUDeGnRksnlhVIAJc3AHZZSHQJ8DEXMhh35TVv2nYhTI3rID7GwjXXw4ocz7RGDD37ky6p39Tl5NB71gT1eSqhZhGHEYHIPXraEBd5+3w9qIuLWlp5Ej/K6Mu4ELioXKCUimCbwy+Cs8UhHFlqcyg4AysOHJwIadXIa8LsY51jnVSGrGOEBZevopmQPNPtyfFY3dmXSS+6Z3RD2Gd6oDnNGJzpSyEk410Ag5uvNDfYzJLCWX9tU8lIxNwdFYmIwpd89HijyRyoGnoJ3entd63cvKfuuix5r+GHyKp1Xm1L5j5AWM6P+z0xigwkiXnt+adexAl1J9wdDxv/pUFEESRF4DG8DFGVtbdH6aR1A5/vD4krO4tC1QYUSeyL5Mvsw8WRqIFHcXtgybtxylljvNcGMV1KXQC8UFDmpGZVDSHx6v3e/BHMrZ7gjoCCfVMZ/cFcQi0W2AIHPYEMH/C95J2r4XbHMRdYXpovpOoT5Ca78gsCAwEAAQ==", "keyDetails": "PKCS1_RSA_PKCS1V5", "validFor": { - "start": "2021-03-14T00:00:00.000Z", - "end": "2022-07-31T00:00:00.000Z" + "start": "2021-03-14T00:00:00Z", + "end": "2022-07-31T00:00:00Z" } }, "logId": { @@ -61,8 +61,8 @@ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEh99xuRi6slBFd8VUJoK/rLigy4bYeSYWO/fE6Br7r0D8NpMI94+A63LR/WvLxpUUGBpY8IJA3iU2telag5CRpA==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { - "start": "2022-07-01T00:00:00.000Z", - "end": "2022-07-31T00:00:00.000Z" + "start": "2022-07-01T00:00:00Z", + "end": "2022-07-31T00:00:00Z" } }, "logId": { @@ -76,7 +76,7 @@ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8gEDKNme8AnXuPBgHjrtXdS6miHqc24CRblNEOFpiJRngeq8Ko73Y+K18yRYVf1DXD4AVLwvKyzdNdl5n0jUSQ==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { - "start": "2022-07-01T00:00:00.000Z" + "start": "2022-07-01T00:00:00Z" } }, "logId": { @@ -87,25 +87,22 @@ "timestampAuthorities": [ { "subject": { - "organization": "GitHub, Inc.", - "commonName": "Internal Services Root - staging" + "organization": "sigstore.dev", + "commonName": "sigstore-tsa-selfsigned" }, - "uri": "tsa.github.internal", + "uri": "https://timestamp.sigstage.dev/api/v1/timestamp", "certChain": { "certificates": [ { - "rawBytes": "MIICEzCCAZigAwIBAgIUMpRykCcZaSOBipYce6r2DlnM7vUwCgYIKoZIzj0EAwMwPDEVMBMGA1UEChMMR2l0SHViLCBJbmMuMSMwIQYDVQQDExpUU0EgaW50ZXJtZWRpYXRlIC0gc3RhZ2luZzAeFw0yMzA2MTQxMjAwMDBaFw0yNDA2MTMxMjAwMDBaMDwxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEjMCEGA1UEAxMaVFNBIFRpbWVzdGFtcGluZyAtIHN0YWdpbmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATWAMg1BEHAzb03PHUKJiRJZdXcKIL0K/ks3Ylq5F5YDRIxUN4o8yeIaCWXa6i16zi8nXMFsa+3XrYM8mUyi9F6o3gwdjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUr+RZdcTNo31p3FuR0pajelcnr40wHwYDVR0jBBgwFoAUCmpQzrB6hAnlizGx37LrhKEzsT4wFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwCgYIKoZIzj0EAwMDaQAwZgIxAIPUlZB2/p5rpCM3HCn1R8G5TIIW6aZPKtfPWDkNQY0bpFu6e8Dkm2TV3jfgYExuBgIxAOA+vTlDDJoz/qTMMs8VSpw3AMgktlMEhd8V0E+aLW5OizfphuiidkqkqkbCwRSW1w==" - }, - { - "rawBytes": "MIICNzCCAb6gAwIBAgIUUXRsBKgGXjrJbdJCQPJMsjfyJcYwCgYIKoZIzj0EAwMwQjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMSkwJwYDVQQDEyBJbnRlcm5hbCBTZXJ2aWNlcyBSb290IC0gc3RhZ2luZzAeFw0yMzA2MTQwMDAwMDBaFw0yODA2MTIwMDAwMDBaMDwxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEjMCEGA1UEAxMaVFNBIGludGVybWVkaWF0ZSAtIHN0YWdpbmcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAS/upihrvu/9+w1Ybfog3B1a8KfQa1bn7DLcJz2iumo+oCfg2bcbyRWygu8zRmrzJKp4HgQHC4LZJEEWm/MNIN1o6wVVmiDTZw01tk4aInmRVF13VKMscdzW5Ho4sYaeOejezB5MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDCDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQKalDOsHqECeWLMbHfsuuEoTOxPjAfBgNVHSMEGDAWgBR04GYtT79vaQmAEPPEte8q+W1KRTAKBggqhkjOPQQDAwNnADBkAjBOTWZP1QYnmHpFqL73eSzhmSLiHs9pXsQghK0p8pvlAg0R9bxAyXGIZ8qx+k2iIGcCMDRQIScz0gu2Xef3++p2vFYouBsIKbqxv0raJuIlmGiYEvb22MDpAitevKAgqNVMEg==" + "rawBytes": "MIICDzCCAZagAwIBAgIUCjWhBmHV4kFzxomWp/J98n4DfKcwCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTAzMjgwOTE0MDZaFw0zNTAzMjYwODE0MDZaMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEx1v5F3HpD9egHuknpBFlRz7QBRDJu4aeVzt9zJLRY0lvmx1lF7WBM2c9AN8ZGPQsmDqHlJN2R/7+RxLkvlLzkc19IOx38t7mGGEcB7agUDdCF/Ky3RTLSK0Xo/0AgHQdo2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFKj8ZPYo3i7mO3NPVIxSxOGc3VOlMB8GA1UdIwQYMBaAFDsgRlletTJNRzDObmPuc3RH8gR9MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMDA2cAMGQCMESvVS6GGtF33+J19TfwENWJXjRv4i0/HQFwLUSkX6TfV7g0nG8VnqNHJLvEpAtOjQIwUD3uywTXorQP1DgbV09rF9Yen+CEqs/iEpieJWPst280SSOZ5Na+dyPVk9/8SFk6" }, { - "rawBytes": "MIICCDCCAY6gAwIBAgIULHHP/UhbXJbdyZfT6gHgTzIYF4EwCgYIKoZIzj0EAwMwQjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMSkwJwYDVQQDEyBJbnRlcm5hbCBTZXJ2aWNlcyBSb290IC0gc3RhZ2luZzAeFw0yMzA2MTQwMDAwMDBaFw0zMzA2MTEwMDAwMDBaMEIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEpMCcGA1UEAxMgSW50ZXJuYWwgU2VydmljZXMgUm9vdCAtIHN0YWdpbmcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASocByKBUdzgtqRXcpe/AE5oPoDMWTQqz1/jUQOA8qoEjYBXg9gfGU5KHK/UdwQc4lxbZEA9nJS9vUQAMVV5Es9B4thNHThKR4hFmCL8kKIEoMzXx282Qr6x4ZHYk4tQsCjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBR04GYtT79vaQmAEPPEte8q+W1KRTAKBggqhkjOPQQDAwNoADBlAjBBOu3RtlH1FLvfHPhyoWJHgm+PSNrsWQLRkmWQgAfNPYsfO5fWyhAebMV3FpKVPBICMQCVaie4NAsGi+AHLDhGnPn4Qptz0LBH2So6AVJS24ICeDUDQxKeUTNkUsy6Qgg97/4=" + "rawBytes": "MIIB9zCCAXygAwIBAgIUCPExEFKiQh0dP4sp5ltmSYSSkFUwCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTAzMjgwOTE0MDZaFw0zNTAzMjYwODE0MDZaMDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATt0tIDWyo4ARfL9BaSo0W5bJQEbKJTU/u7llvdjSI5aTkOAJa8tixn2+LEfPG4dMFdsMPtsIuU1qn2OqFiuMk6vHv/c+az25RQVY1oo50iMb0jIL3N4FgwhPFpZnCbQPOjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQ7IEZZXrUyTUcwzm5j7nN0R/IEfTAKBggqhkjOPQQDAwNpADBmAjEA2MI1VXgbf3dUOSc95hSRypBKOab18eh2xzQtxUsHvWeY+1iFgyMluUuNR6taoSmFAjEA31m2czguZhKYX+4JSKu5pRYhBTXAd8KKQ3xdPRX/qCaLvT2qJAEQ1YQM3EJRrtI7" } ] }, "validFor": { - "start": "2023-06-15T00:00:00Z" + "start": "2025-04-09T00:00:00Z" } } ] diff --git a/test/assets/staging-tuf/targets/90659875a02f73d1026055427c6d857c556e410e23748ff88aeb493227610fd2f5fbdd95ef2a21565f91438dfb3e073f50c4c9dd06f9a601b5d9b064d5cb60b4.fulcio_intermediate.crt.pem b/test/assets/staging-tuf/targets/90659875a02f73d1026055427c6d857c556e410e23748ff88aeb493227610fd2f5fbdd95ef2a21565f91438dfb3e073f50c4c9dd06f9a601b5d9b064d5cb60b4.fulcio_intermediate.crt.pem deleted file mode 100644 index d94a2aa40..000000000 --- a/test/assets/staging-tuf/targets/90659875a02f73d1026055427c6d857c556e410e23748ff88aeb493227610fd2f5fbdd95ef2a21565f91438dfb3e073f50c4c9dd06f9a601b5d9b064d5cb60b4.fulcio_intermediate.crt.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICGTCCAaCgAwIBAgITJta/okfgHvjabGm1BOzuhrwA1TAKBggqhkjOPQQDAzAq -MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIy -MDQxNDIxMzg0MFoXDTMyMDMyMjE2NTA0NVowNzEVMBMGA1UEChMMc2lnc3RvcmUu -ZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwdjAQBgcqhkjOPQIB -BgUrgQQAIgNiAASosAySWJQ/tK5r8T5aHqavk0oI+BKQbnLLdmOMRXHQF/4Hx9Kt -NfpcdjH9hNKQSBxSlLFFN3tvFCco0qFBzWYwZtsYsBe1l91qYn/9VHFTaEVwYQWI -JEEvrs0fvPuAqjajezB5MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEF -BQcDAzASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRxhjCmFHxib/n31vQF -Gn9f/+tvrDAfBgNVHSMEGDAWgBT/QjK6aH2rOnCv3AzUGuI+h49mZTAKBggqhkjO -PQQDAwNnADBkAjAM1lbKkcqQlE/UspMTbWNo1y2TaJ44tx3l/FJFceTSdDZ+0W1O -HHeU4twie/lq8XgCMHQxgEv26xNNiAGyPXbkYgrDPvbOqp0UeWX4mJnLSrBr3aN/ -KX1SBrKQu220FmVL0Q== ------END CERTIFICATE----- diff --git a/test/assets/staging-tuf/targets/910d899c7763563095a0fe684c8477573fedc19a78586de6ecfbfd8f289f5423.ctfe_2022.pub b/test/assets/staging-tuf/targets/910d899c7763563095a0fe684c8477573fedc19a78586de6ecfbfd8f289f5423.ctfe_2022.pub deleted file mode 100644 index 3023b8618..000000000 --- a/test/assets/staging-tuf/targets/910d899c7763563095a0fe684c8477573fedc19a78586de6ecfbfd8f289f5423.ctfe_2022.pub +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEh99xuRi6slBFd8VUJoK/rLigy4bY -eSYWO/fE6Br7r0D8NpMI94+A63LR/WvLxpUUGBpY8IJA3iU2telag5CRpA== ------END PUBLIC KEY----- diff --git a/test/assets/staging-tuf/targets/ab975a75600fc366a837536d0dcba841b755552d21bb114498ff8ac9d2403f76643f5b91269bce5d124a365514719a3edee9dcc2b046cb173f51af659911fcd3.ctfe_2022.pub b/test/assets/staging-tuf/targets/ab975a75600fc366a837536d0dcba841b755552d21bb114498ff8ac9d2403f76643f5b91269bce5d124a365514719a3edee9dcc2b046cb173f51af659911fcd3.ctfe_2022.pub deleted file mode 100644 index 3023b8618..000000000 --- a/test/assets/staging-tuf/targets/ab975a75600fc366a837536d0dcba841b755552d21bb114498ff8ac9d2403f76643f5b91269bce5d124a365514719a3edee9dcc2b046cb173f51af659911fcd3.ctfe_2022.pub +++ /dev/null @@ -1,4 +0,0 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEh99xuRi6slBFd8VUJoK/rLigy4bY -eSYWO/fE6Br7r0D8NpMI94+A63LR/WvLxpUUGBpY8IJA3iU2telag5CRpA== ------END PUBLIC KEY----- diff --git a/test/assets/staging-tuf/targets/acf0438a71de70bbf1813c908545281e0c4a1e3aafa2ce36b82c1cc24a9cce5169e9dcfe85c31bb4f662e94fdd9a686fa54fbbfccff1888e51ebd73924c12495.trusted_root.json b/test/assets/staging-tuf/targets/acf0438a71de70bbf1813c908545281e0c4a1e3aafa2ce36b82c1cc24a9cce5169e9dcfe85c31bb4f662e94fdd9a686fa54fbbfccff1888e51ebd73924c12495.trusted_root.json deleted file mode 100644 index f5b8853e7..000000000 --- a/test/assets/staging-tuf/targets/acf0438a71de70bbf1813c908545281e0c4a1e3aafa2ce36b82c1cc24a9cce5169e9dcfe85c31bb4f662e94fdd9a686fa54fbbfccff1888e51ebd73924c12495.trusted_root.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1", - "tlogs": [ - { - "baseUrl": "https://rekor.sigstage.dev", - "hashAlgorithm": "SHA2_256", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDODRU688UYGuy54mNUlaEBiQdTE9nYLr0lg6RXowI/QV/RE1azBn4Eg5/2uTOMbhB1/gfcHzijzFi9Tk+g1Prg==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "2021-01-12T11:53:27.000Z" - } - }, - "logId": { - "keyId": "0y8wo8MtY5wrdiIFohx7sHeI5oKDpK5vQhGHI6G+pJY=" - } - } - ], - "certificateAuthorities": [ - { - "subject": { - "organization": "sigstore.dev", - "commonName": "sigstore" - }, - "uri": "https://fulcio.sigstage.dev", - "certChain": { - "certificates": [ - { - "rawBytes": "MIICGTCCAaCgAwIBAgITJta/okfgHvjabGm1BOzuhrwA1TAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIyMDQxNDIxMzg0MFoXDTMyMDMyMjE2NTA0NVowNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASosAySWJQ/tK5r8T5aHqavk0oI+BKQbnLLdmOMRXHQF/4Hx9KtNfpcdjH9hNKQSBxSlLFFN3tvFCco0qFBzWYwZtsYsBe1l91qYn/9VHFTaEVwYQWIJEEvrs0fvPuAqjajezB5MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDAzASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRxhjCmFHxib/n31vQFGn9f/+tvrDAfBgNVHSMEGDAWgBT/QjK6aH2rOnCv3AzUGuI+h49mZTAKBggqhkjOPQQDAwNnADBkAjAM1lbKkcqQlE/UspMTbWNo1y2TaJ44tx3l/FJFceTSdDZ+0W1OHHeU4twie/lq8XgCMHQxgEv26xNNiAGyPXbkYgrDPvbOqp0UeWX4mJnLSrBr3aN/KX1SBrKQu220FmVL0Q==" - }, - { - "rawBytes": "MIIB9jCCAXugAwIBAgITDdEJvluliE0AzYaIE4jTMdnFTzAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIyMDMyNTE2NTA0NloXDTMyMDMyMjE2NTA0NVowKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMo9BUNk9QIYisYysC24+2OytoV72YiLonYcqR3yeVnYziPt7Xv++CYE8yoCTiwedUECCWKOcvQKRCJZb9ht4Hzy+VvBx36hK+C6sECCSR0x6pPSiz+cTk1f788ZjBlUZaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP9CMrpofas6cK/cDNQa4j6Hj2ZlMB8GA1UdIwQYMBaAFP9CMrpofas6cK/cDNQa4j6Hj2ZlMAoGCCqGSM49BAMDA2kAMGYCMQD+kojuzMwztNay9Ibzjuk//ZL5m6T2OCsm45l1lY004pcb984L926BowodoirFMcMCMQDIJtFHhP/1D3a+M3dAGomOb6O4CmTry3TTPbPsAFnv22YA0Y+P21NVoxKDjdu0tkw=" - } - ] - }, - "validFor": { - "start": "2022-04-14T21:38:40.000Z" - } - } - ], - "ctlogs": [ - { - "baseUrl": "https://ctfe.sigstage.dev/test", - "hashAlgorithm": "SHA2_256", - "publicKey": { - "rawBytes": "MIICCgKCAgEA27A2MPQXm0I0v7/Ly5BIauDjRZF5Jor9vU+QheoE2UIIsZHcyYq3slHzSSHy2lLj1ZD2d91CtJ492ZXqnBmsr4TwZ9jQ05tW2mGIRI8u2DqN8LpuNYZGz/f9SZrjhQQmUttqWmtu3UoLfKz6NbNXUnoo+NhZFcFRLXJ8VporVhuiAmL7zqT53cXR3yQfFPCUDeGnRksnlhVIAJc3AHZZSHQJ8DEXMhh35TVv2nYhTI3rID7GwjXXw4ocz7RGDD37ky6p39Tl5NB71gT1eSqhZhGHEYHIPXraEBd5+3w9qIuLWlp5Ej/K6Mu4ELioXKCUimCbwy+Cs8UhHFlqcyg4AysOHJwIadXIa8LsY51jnVSGrGOEBZevopmQPNPtyfFY3dmXSS+6Z3RD2Gd6oDnNGJzpSyEk410Ag5uvNDfYzJLCWX9tU8lIxNwdFYmIwpd89HijyRyoGnoJ3entd63cvKfuuix5r+GHyKp1Xm1L5j5AWM6P+z0xigwkiXnt+adexAl1J9wdDxv/pUFEESRF4DG8DFGVtbdH6aR1A5/vD4krO4tC1QYUSeyL5Mvsw8WRqIFHcXtgybtxylljvNcGMV1KXQC8UFDmpGZVDSHx6v3e/BHMrZ7gjoCCfVMZ/cFcQi0W2AIHPYEMH/C95J2r4XbHMRdYXpovpOoT5Ca78gsCAwEAAQ==", - "keyDetails": "PKCS1_RSA_PKCS1V5", - "validFor": { - "start": "2021-03-14T00:00:00.000Z", - "end": "2022-07-31T00:00:00.000Z" - } - }, - "logId": { - "keyId": "G3wUKk6ZK6ffHh/FdCRUE2wVekyzHEEIpSG4savnv0w=" - } - }, - { - "baseUrl": "https://ctfe.sigstage.dev/2022", - "hashAlgorithm": "SHA2_256", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEh99xuRi6slBFd8VUJoK/rLigy4bYeSYWO/fE6Br7r0D8NpMI94+A63LR/WvLxpUUGBpY8IJA3iU2telag5CRpA==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "2022-07-01T00:00:00.000Z", - "end": "2022-07-31T00:00:00.000Z" - } - }, - "logId": { - "keyId": "++JKOMQt7SJ3ynUHnCfnDhcKP8/58J4TueMqXuk3HmA=" - } - }, - { - "baseUrl": "https://ctfe.sigstage.dev/2022-2", - "hashAlgorithm": "SHA2_256", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8gEDKNme8AnXuPBgHjrtXdS6miHqc24CRblNEOFpiJRngeq8Ko73Y+K18yRYVf1DXD4AVLwvKyzdNdl5n0jUSQ==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "2022-07-01T00:00:00.000Z" - } - }, - "logId": { - "keyId": "KzC83GiIyeLh2CYpXnQfSDkxlgLynDPLXkNA/rKshno=" - } - } - ], - "timestampAuthorities": [ - { - "subject": { - "organization": "GitHub, Inc.", - "commonName": "Internal Services Root - staging" - }, - "uri": "tsa.github.internal", - "certChain": { - "certificates": [ - { - "rawBytes": "MIICEzCCAZigAwIBAgIUMpRykCcZaSOBipYce6r2DlnM7vUwCgYIKoZIzj0EAwMwPDEVMBMGA1UEChMMR2l0SHViLCBJbmMuMSMwIQYDVQQDExpUU0EgaW50ZXJtZWRpYXRlIC0gc3RhZ2luZzAeFw0yMzA2MTQxMjAwMDBaFw0yNDA2MTMxMjAwMDBaMDwxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEjMCEGA1UEAxMaVFNBIFRpbWVzdGFtcGluZyAtIHN0YWdpbmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATWAMg1BEHAzb03PHUKJiRJZdXcKIL0K/ks3Ylq5F5YDRIxUN4o8yeIaCWXa6i16zi8nXMFsa+3XrYM8mUyi9F6o3gwdjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUr+RZdcTNo31p3FuR0pajelcnr40wHwYDVR0jBBgwFoAUCmpQzrB6hAnlizGx37LrhKEzsT4wFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwCgYIKoZIzj0EAwMDaQAwZgIxAIPUlZB2/p5rpCM3HCn1R8G5TIIW6aZPKtfPWDkNQY0bpFu6e8Dkm2TV3jfgYExuBgIxAOA+vTlDDJoz/qTMMs8VSpw3AMgktlMEhd8V0E+aLW5OizfphuiidkqkqkbCwRSW1w==" - }, - { - "rawBytes": "MIICNzCCAb6gAwIBAgIUUXRsBKgGXjrJbdJCQPJMsjfyJcYwCgYIKoZIzj0EAwMwQjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMSkwJwYDVQQDEyBJbnRlcm5hbCBTZXJ2aWNlcyBSb290IC0gc3RhZ2luZzAeFw0yMzA2MTQwMDAwMDBaFw0yODA2MTIwMDAwMDBaMDwxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEjMCEGA1UEAxMaVFNBIGludGVybWVkaWF0ZSAtIHN0YWdpbmcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAS/upihrvu/9+w1Ybfog3B1a8KfQa1bn7DLcJz2iumo+oCfg2bcbyRWygu8zRmrzJKp4HgQHC4LZJEEWm/MNIN1o6wVVmiDTZw01tk4aInmRVF13VKMscdzW5Ho4sYaeOejezB5MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDCDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQKalDOsHqECeWLMbHfsuuEoTOxPjAfBgNVHSMEGDAWgBR04GYtT79vaQmAEPPEte8q+W1KRTAKBggqhkjOPQQDAwNnADBkAjBOTWZP1QYnmHpFqL73eSzhmSLiHs9pXsQghK0p8pvlAg0R9bxAyXGIZ8qx+k2iIGcCMDRQIScz0gu2Xef3++p2vFYouBsIKbqxv0raJuIlmGiYEvb22MDpAitevKAgqNVMEg==" - }, - { - "rawBytes": "MIICCDCCAY6gAwIBAgIULHHP/UhbXJbdyZfT6gHgTzIYF4EwCgYIKoZIzj0EAwMwQjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMSkwJwYDVQQDEyBJbnRlcm5hbCBTZXJ2aWNlcyBSb290IC0gc3RhZ2luZzAeFw0yMzA2MTQwMDAwMDBaFw0zMzA2MTEwMDAwMDBaMEIxFTATBgNVBAoTDEdpdEh1YiwgSW5jLjEpMCcGA1UEAxMgSW50ZXJuYWwgU2VydmljZXMgUm9vdCAtIHN0YWdpbmcwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASocByKBUdzgtqRXcpe/AE5oPoDMWTQqz1/jUQOA8qoEjYBXg9gfGU5KHK/UdwQc4lxbZEA9nJS9vUQAMVV5Es9B4thNHThKR4hFmCL8kKIEoMzXx282Qr6x4ZHYk4tQsCjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgECMB0GA1UdDgQWBBR04GYtT79vaQmAEPPEte8q+W1KRTAKBggqhkjOPQQDAwNoADBlAjBBOu3RtlH1FLvfHPhyoWJHgm+PSNrsWQLRkmWQgAfNPYsfO5fWyhAebMV3FpKVPBICMQCVaie4NAsGi+AHLDhGnPn4Qptz0LBH2So6AVJS24ICeDUDQxKeUTNkUsy6Qgg97/4=" - } - ] - }, - "validFor": { - "start": "2023-06-15T00:00:00Z" - } - } - ] -} diff --git a/test/assets/staging-tuf/targets/b861189e48df51186a39612230fba6b02af951f7b35ad9375e8ca182d0e085d470e26d69f7cd4d7450a0f223991e8e5a4ddf8f1968caa15255de8e37035af43a.ctfe.pub b/test/assets/staging-tuf/targets/b861189e48df51186a39612230fba6b02af951f7b35ad9375e8ca182d0e085d470e26d69f7cd4d7450a0f223991e8e5a4ddf8f1968caa15255de8e37035af43a.ctfe.pub deleted file mode 100644 index 39512c214..000000000 --- a/test/assets/staging-tuf/targets/b861189e48df51186a39612230fba6b02af951f7b35ad9375e8ca182d0e085d470e26d69f7cd4d7450a0f223991e8e5a4ddf8f1968caa15255de8e37035af43a.ctfe.pub +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN RSA PUBLIC KEY----- -MIICCgKCAgEA27A2MPQXm0I0v7/Ly5BIauDjRZF5Jor9vU+QheoE2UIIsZHcyYq3 -slHzSSHy2lLj1ZD2d91CtJ492ZXqnBmsr4TwZ9jQ05tW2mGIRI8u2DqN8LpuNYZG -z/f9SZrjhQQmUttqWmtu3UoLfKz6NbNXUnoo+NhZFcFRLXJ8VporVhuiAmL7zqT5 -3cXR3yQfFPCUDeGnRksnlhVIAJc3AHZZSHQJ8DEXMhh35TVv2nYhTI3rID7GwjXX -w4ocz7RGDD37ky6p39Tl5NB71gT1eSqhZhGHEYHIPXraEBd5+3w9qIuLWlp5Ej/K -6Mu4ELioXKCUimCbwy+Cs8UhHFlqcyg4AysOHJwIadXIa8LsY51jnVSGrGOEBZev -opmQPNPtyfFY3dmXSS+6Z3RD2Gd6oDnNGJzpSyEk410Ag5uvNDfYzJLCWX9tU8lI -xNwdFYmIwpd89HijyRyoGnoJ3entd63cvKfuuix5r+GHyKp1Xm1L5j5AWM6P+z0x -igwkiXnt+adexAl1J9wdDxv/pUFEESRF4DG8DFGVtbdH6aR1A5/vD4krO4tC1QYU -SeyL5Mvsw8WRqIFHcXtgybtxylljvNcGMV1KXQC8UFDmpGZVDSHx6v3e/BHMrZ7g -joCCfVMZ/cFcQi0W2AIHPYEMH/C95J2r4XbHMRdYXpovpOoT5Ca78gsCAwEAAQ== ------END RSA PUBLIC KEY----- diff --git a/test/assets/staging-tuf/targets/bd7a6812a1f239dfddbbb19d36c7423d21510da56d466ba5018401959cd66037.ctfe.pub b/test/assets/staging-tuf/targets/bd7a6812a1f239dfddbbb19d36c7423d21510da56d466ba5018401959cd66037.ctfe.pub deleted file mode 100644 index 39512c214..000000000 --- a/test/assets/staging-tuf/targets/bd7a6812a1f239dfddbbb19d36c7423d21510da56d466ba5018401959cd66037.ctfe.pub +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN RSA PUBLIC KEY----- -MIICCgKCAgEA27A2MPQXm0I0v7/Ly5BIauDjRZF5Jor9vU+QheoE2UIIsZHcyYq3 -slHzSSHy2lLj1ZD2d91CtJ492ZXqnBmsr4TwZ9jQ05tW2mGIRI8u2DqN8LpuNYZG -z/f9SZrjhQQmUttqWmtu3UoLfKz6NbNXUnoo+NhZFcFRLXJ8VporVhuiAmL7zqT5 -3cXR3yQfFPCUDeGnRksnlhVIAJc3AHZZSHQJ8DEXMhh35TVv2nYhTI3rID7GwjXX -w4ocz7RGDD37ky6p39Tl5NB71gT1eSqhZhGHEYHIPXraEBd5+3w9qIuLWlp5Ej/K -6Mu4ELioXKCUimCbwy+Cs8UhHFlqcyg4AysOHJwIadXIa8LsY51jnVSGrGOEBZev -opmQPNPtyfFY3dmXSS+6Z3RD2Gd6oDnNGJzpSyEk410Ag5uvNDfYzJLCWX9tU8lI -xNwdFYmIwpd89HijyRyoGnoJ3entd63cvKfuuix5r+GHyKp1Xm1L5j5AWM6P+z0x -igwkiXnt+adexAl1J9wdDxv/pUFEESRF4DG8DFGVtbdH6aR1A5/vD4krO4tC1QYU -SeyL5Mvsw8WRqIFHcXtgybtxylljvNcGMV1KXQC8UFDmpGZVDSHx6v3e/BHMrZ7g -joCCfVMZ/cFcQi0W2AIHPYEMH/C95J2r4XbHMRdYXpovpOoT5Ca78gsCAwEAAQ== ------END RSA PUBLIC KEY----- diff --git a/test/assets/staging-tuf/targets/c69ae618883a0c89c282c0943a1ad0c16b0a7788f74e47a1adefc631dac48a0c4449d8c3de7455ae7d772e43c4a87e341f180b0614a46a86006969f8a7b84532.fulcio.crt.pem b/test/assets/staging-tuf/targets/c69ae618883a0c89c282c0943a1ad0c16b0a7788f74e47a1adefc631dac48a0c4449d8c3de7455ae7d772e43c4a87e341f180b0614a46a86006969f8a7b84532.fulcio.crt.pem deleted file mode 100644 index 47a5becff..000000000 --- a/test/assets/staging-tuf/targets/c69ae618883a0c89c282c0943a1ad0c16b0a7788f74e47a1adefc631dac48a0c4449d8c3de7455ae7d772e43c4a87e341f180b0614a46a86006969f8a7b84532.fulcio.crt.pem +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIB9jCCAXugAwIBAgITDdEJvluliE0AzYaIE4jTMdnFTzAKBggqhkjOPQQDAzAq -MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIy -MDMyNTE2NTA0NloXDTMyMDMyMjE2NTA0NVowKjEVMBMGA1UEChMMc2lnc3RvcmUu -ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMo9 -BUNk9QIYisYysC24+2OytoV72YiLonYcqR3yeVnYziPt7Xv++CYE8yoCTiwedUEC -CWKOcvQKRCJZb9ht4Hzy+VvBx36hK+C6sECCSR0x6pPSiz+cTk1f788ZjBlUZaNj -MGEwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP9C -Mrpofas6cK/cDNQa4j6Hj2ZlMB8GA1UdIwQYMBaAFP9CMrpofas6cK/cDNQa4j6H -j2ZlMAoGCCqGSM49BAMDA2kAMGYCMQD+kojuzMwztNay9Ibzjuk//ZL5m6T2OCsm -45l1lY004pcb984L926BowodoirFMcMCMQDIJtFHhP/1D3a+M3dAGomOb6O4CmTr -y3TTPbPsAFnv22YA0Y+P21NVoxKDjdu0tkw= ------END CERTIFICATE----- diff --git a/test/assets/staging-tuf/targets/cb9a48c332a0d515db7760ad6972a09a0f4ed721fe5e839b70371e0d0802abe2.signing_config.v0.2.json b/test/assets/staging-tuf/targets/cb9a48c332a0d515db7760ad6972a09a0f4ed721fe5e839b70371e0d0802abe2.signing_config.v0.2.json new file mode 100644 index 000000000..fe66ad97b --- /dev/null +++ b/test/assets/staging-tuf/targets/cb9a48c332a0d515db7760ad6972a09a0f4ed721fe5e839b70371e0d0802abe2.signing_config.v0.2.json @@ -0,0 +1,45 @@ +{ + "mediaType": "application/vnd.dev.sigstore.signingconfig.v0.2+json", + "caUrls": [ + { + "url": "https://fulcio.sigstage.dev", + "majorApiVersion": 1, + "validFor": { + "start": "2022-04-14T21:38:40Z" + } + } + ], + "oidcUrls": [ + { + "url": "https://oauth2.sigstage.dev/auth", + "majorApiVersion": 1, + "validFor": { + "start": "2025-04-16T00:00:00Z" + } + } + ], + "rekorTlogUrls": [ + { + "url": "https://rekor.sigstage.dev", + "majorApiVersion": 1, + "validFor": { + "start": "2021-01-12T11:53:27Z" + } + } + ], + "tsaUrls": [ + { + "url": "https://timestamp.sigstage.dev/api/v1/timestamp", + "majorApiVersion": 1, + "validFor": { + "start": "2025-04-09T00:00:00Z" + } + } + ], + "rekorTlogConfig": { + "selector": "ANY" + }, + "tsaConfig": { + "selector": "ANY" + } +} \ No newline at end of file diff --git a/test/assets/staging-tuf/targets/registry.npmjs.org/7a8ec9678ad824cdccaa7a6dc0961caf8f8df61bc7274189122c123446248426.keys.json b/test/assets/staging-tuf/targets/registry.npmjs.org/7a8ec9678ad824cdccaa7a6dc0961caf8f8df61bc7274189122c123446248426.keys.json deleted file mode 100644 index f5667a5f0..000000000 --- a/test/assets/staging-tuf/targets/registry.npmjs.org/7a8ec9678ad824cdccaa7a6dc0961caf8f8df61bc7274189122c123446248426.keys.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "keys": [ - { - "keyId": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "keyUsage": "npm:signatures", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "1999-01-01T00:00:00.000Z" - } - } - }, - { - "keyId": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "keyUsage": "npm:attestations", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "2022-12-01T00:00:00.000Z" - } - } - } - ] -} diff --git a/test/assets/staging-tuf/targets/registry.npmjs.org/881a853ee92d8cf513b07c164fea36b22a7305c256125bdfffdc5c65a4205c4c3fc2b5bcc98964349167ea68d40b8cd02551fcaa870a30d4601ba1caf6f63699.keys.json b/test/assets/staging-tuf/targets/registry.npmjs.org/881a853ee92d8cf513b07c164fea36b22a7305c256125bdfffdc5c65a4205c4c3fc2b5bcc98964349167ea68d40b8cd02551fcaa870a30d4601ba1caf6f63699.keys.json deleted file mode 100644 index f5667a5f0..000000000 --- a/test/assets/staging-tuf/targets/registry.npmjs.org/881a853ee92d8cf513b07c164fea36b22a7305c256125bdfffdc5c65a4205c4c3fc2b5bcc98964349167ea68d40b8cd02551fcaa870a30d4601ba1caf6f63699.keys.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "keys": [ - { - "keyId": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "keyUsage": "npm:signatures", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "1999-01-01T00:00:00.000Z" - } - } - }, - { - "keyId": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA", - "keyUsage": "npm:attestations", - "publicKey": { - "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==", - "keyDetails": "PKIX_ECDSA_P256_SHA_256", - "validFor": { - "start": "2022-12-01T00:00:00.000Z" - } - } - } - ] -} diff --git a/test/assets/staging-tuf/timestamp.json b/test/assets/staging-tuf/timestamp.json index 5aa16c8e3..8feb575b0 100644 --- a/test/assets/staging-tuf/timestamp.json +++ b/test/assets/staging-tuf/timestamp.json @@ -1,24 +1,19 @@ { - "signed": { - "_type": "timestamp", - "spec_version": "1.0", - "version": 4, - "expires": "2028-09-19T22:52:25Z", - "meta": { - "snapshot.json": { - "length": 1043, - "hashes": { - "sha256": "30eee4304ab6d1d9545f8510953d5e2f2d877307216bcd60b7ce27302c4e3d02", - "sha512": "9149780f6daf49b70e3afef83ff1a158095f539c01d474ca9e97f8c8bd9d451b266b1444223b15f15fe8d5db09d3b0da94f1f6d6bbac9c3c0e7bc62c2905003d" - }, - "version": 4 - } - } - }, - "signatures": [ - { - "keyid": "314ae73abd3012fc73bfcc3783e31d03852716597642b891d6a33155c4baf600", - "sig": "3046022100cc12bcab1c1f9776f0b98232a12567822816de0acbe9cc7026ec9370619f30f8022100ef0f6d0bb55f4fba134a8a6c50739a6d90d8d09cfe54e51d1adf158d65aa1870" - } - ] + "signatures": [ + { + "keyid": "c3479007e861445ce5dc109d9661ed77b35bbc0e3f161852c46114266fc2daa4", + "sig": "30450220665b03b09118979b8c8d93b55077279e0424ae5802a0f59e14fdccef49b0c420022100f2fd10223ca19ee7e0671839e69508e8fd4a5ea875cf7e19fe6d0d77acd604a3" + } + ], + "signed": { + "_type": "timestamp", + "expires": "2025-05-09T07:17:49Z", + "meta": { + "snapshot.json": { + "version": 13 + } + }, + "spec_version": "1.0", + "version": 280 + } } \ No newline at end of file diff --git a/test/unit/internal/test_trust.py b/test/unit/internal/test_trust.py index d9c1ada2e..dbb2d1da8 100644 --- a/test/unit/internal/test_trust.py +++ b/test/unit/internal/test_trust.py @@ -30,7 +30,7 @@ _is_timerange_valid, ) from sigstore._utils import load_pem_public_key -from sigstore.errors import Error, RootError +from sigstore.errors import Error class TestCertificateAuthority: @@ -96,7 +96,7 @@ def test_trust_root_tuf_caches_and_requests(mock_staging_tuf, tuf_dirs): # keep track of requests the TrustUpdater invoked by TrustedRoot makes reqs, fail_reqs = mock_staging_tuf - trust_root = ClientTrustConfig.staging() + trust_config = ClientTrustConfig.staging() # metadata was "downloaded" from staging expected = [ "root.json", @@ -111,31 +111,31 @@ def test_trust_root_tuf_caches_and_requests(mock_staging_tuf, tuf_dirs): # Don't expect trusted_root.json request as it's cached already expected_requests = { "timestamp.json": 1, - "4.snapshot.json": 1, - "4.targets.json": 1, + "13.snapshot.json": 1, + "13.targets.json": 1, } - expected_fail_reqs = {"5.root.json": 1} + expected_fail_reqs = {"12.root.json": 1} assert reqs == expected_requests assert fail_reqs == expected_fail_reqs - trust_root.ct_keyring(KeyringPurpose.VERIFY) - trust_root.rekor_keyring(KeyringPurpose.VERIFY) + trust_config.trusted_root.ct_keyring(KeyringPurpose.VERIFY) + trust_config.trusted_root.rekor_keyring(KeyringPurpose.VERIFY) # no new requests assert reqs == expected_requests assert fail_reqs == expected_fail_reqs # New trust root (and TrustUpdater instance), same cache dirs - trust_root = ClientTrustConfig.staging() + trust_config = ClientTrustConfig.staging() # Expect new timestamp and root requests expected_requests["timestamp.json"] += 1 - expected_fail_reqs["5.root.json"] += 1 + expected_fail_reqs["12.root.json"] += 1 assert reqs == expected_requests assert fail_reqs == expected_fail_reqs - trust_root.ct_keyring(purpose=KeyringPurpose.VERIFY) - trust_root.rekor_keyring(purpose=KeyringPurpose.VERIFY) + trust_config.trusted_root.ct_keyring(purpose=KeyringPurpose.VERIFY) + trust_config.trusted_root.rekor_keyring(purpose=KeyringPurpose.VERIFY) # Expect no requests assert reqs == expected_requests assert fail_reqs == expected_fail_reqs @@ -148,15 +148,15 @@ def test_trust_root_tuf_offline(mock_staging_tuf, tuf_dirs): # keep track of requests the TrustUpdater invoked by TrustedRoot makes reqs, fail_reqs = mock_staging_tuf - trust_root = ClientTrustConfig.staging(offline=True) + trust_config = ClientTrustConfig.staging(offline=True) # local TUF metadata is not initialized, nothing is downloaded assert not os.path.exists(data_dir) assert reqs == {} assert fail_reqs == {} - trust_root.ct_keyring(purpose=KeyringPurpose.VERIFY) - trust_root.rekor_keyring(purpose=KeyringPurpose.VERIFY) + trust_config.trusted_root.ct_keyring(purpose=KeyringPurpose.VERIFY) + trust_config.trusted_root.rekor_keyring(purpose=KeyringPurpose.VERIFY) # Still no requests assert reqs == {} @@ -240,7 +240,7 @@ def _pem_keys(keys): assert trust_root.get_fulcio_certs() == fulcio_certs # Assert that trust root from offline TUF contains the expected keys/certs - trust_root = ClientTrustConfig.staging(offline=True).trust_root + trust_root = ClientTrustConfig.staging(offline=True).trusted_root assert ctfe_keys[0] in get_public_bytes( [ k.key @@ -288,7 +288,9 @@ def _pem_keys(keys): def test_trust_root_tuf_instance_error(): - with pytest.raises(RootError): + # Expect file not found since embedded root.json is not found and + # no local metadata is found + with pytest.raises(FileNotFoundError): ClientTrustConfig.from_tuf("foo.bar") diff --git a/test/unit/test_store.py b/test/unit/test_store.py index 7e546f9bd..50551154f 100644 --- a/test/unit/test_store.py +++ b/test/unit/test_store.py @@ -19,13 +19,25 @@ from sigstore._utils import read_embedded -@pytest.mark.parametrize("env", ["prod", "staging"]) +@pytest.mark.parametrize( + "env", + [ + "https://tuf-repo-cdn.sigstore.dev", + "https://tuf-repo-cdn.sigstage.dev", + ], +) def test_store_reads_root_json(env): root_json = read_embedded("root.json", env) assert json.loads(root_json) -@pytest.mark.parametrize("env", ["prod", "staging"]) +@pytest.mark.parametrize( + "env", + [ + "https://tuf-repo-cdn.sigstore.dev", + "https://tuf-repo-cdn.sigstage.dev", + ], +) def test_store_reads_targets_json(env): trusted_root_json = read_embedded("trusted_root.json", env) assert json.loads(trusted_root_json) From ddc0b04f0d723c4271316baac738bdabe46630df Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Mon, 5 May 2025 11:04:39 +0300 Subject: [PATCH 06/17] README: Update default oidc-issuer value Default now comes from the trust config. The option is also not especially in conflict with staging. Signed-off-by: Jussi Kukkonen --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fad13d617..e1981a766 100644 --- a/README.md +++ b/README.md @@ -121,8 +121,7 @@ OpenID Connect options: --oidc-disable-ambient-providers Disable ambient OpenID Connect credential detection (e.g. on GitHub Actions) (default: False) - --oidc-issuer URL The OpenID Connect issuer to use (conflicts with - --staging) (default: https://oauth2.sigstore.dev/auth) + --oidc-issuer URL The OpenID Connect issuer to use (default: None) --oauth-force-oob Force an out-of-band OAuth flow and do not automatically start the default web browser (default: False) @@ -185,8 +184,7 @@ OpenID Connect options: --oidc-disable-ambient-providers Disable ambient OpenID Connect credential detection (e.g. on GitHub Actions) (default: False) - --oidc-issuer URL The OpenID Connect issuer to use (conflicts with - --staging) (default: https://oauth2.sigstore.dev/auth) + --oidc-issuer URL The OpenID Connect issuer to use (default: None) --oauth-force-oob Force an out-of-band OAuth flow and do not automatically start the default web browser (default: False) From cc608e301646f5450306480728be4c8d2793230f Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Mon, 5 May 2025 11:26:50 +0300 Subject: [PATCH 07/17] cli: Parse --offline carefully: not all commands have the flag Signed-off-by: Jussi Kukkonen --- sigstore/_cli.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sigstore/_cli.py b/sigstore/_cli.py index d74dc8623..3554100ea 100644 --- a/sigstore/_cli.py +++ b/sigstore/_cli.py @@ -1165,12 +1165,15 @@ def _get_trust_config(args: argparse.Namespace) -> ClientTrustConfig: The configuration may come from explicit argument (--trust-config) or from the TUF repository of the used Sigstore instance. """ + # Some commands do not have offline argument, parse carefully + offline = args.offline if "offline" in args else False + if args.trust_config: return ClientTrustConfig.from_json(args.trust_config.read_text()) elif args.staging: - return ClientTrustConfig.staging(offline=args.offline) + return ClientTrustConfig.staging(offline=offline) else: - return ClientTrustConfig.production(offline=args.offline) + return ClientTrustConfig.production(offline=offline) def _get_identity( From bb0126abf8b9486ee91e431472905565b0c44a84 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Mon, 5 May 2025 11:27:24 +0300 Subject: [PATCH 08/17] trust: TSA are not required in signing config They will be if there are any rekor 2 instances, but currently TSA is not strictly needed. Signed-off-by: Jussi Kukkonen --- sigstore/_internal/trust.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sigstore/_internal/trust.py b/sigstore/_internal/trust.py index a528f6bab..ea18c9155 100644 --- a/sigstore/_internal/trust.py +++ b/sigstore/_internal/trust.py @@ -387,9 +387,7 @@ def get_tsa_urls(self) -> list[str]: but may return more in future. """ url = self._get_valid_service_url(self._inner.tsa_urls) - if not url: - raise Error("No valid Timestamp Authority found in signing config") - return [url] + return [] if url is None else [url] class TrustedRoot: From 37195ccde77314fdf57f5ff168c51873705972d7 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 6 May 2025 13:09:41 +0300 Subject: [PATCH 09/17] CHANGELOG: Mention signing config from TUF This is not a really a user visible change so I'm debating if the item is even needed. Signed-off-by: Jussi Kukkonen --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e77467913..6fcff70c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ All versions prior to 0.9.0 are untracked. * `--trust-config` now requires a file with SigningConfig v0.2, and is able to fully configure the used Sigstore instance [#1358]/(https://github.com/sigstore/sigstore-python/pull/1358) +* By default (when `--trust-config` is not used) signing configuration now comes from + the TUF repository just like the trust root ## [3.6.2] From f94c3f017c92d9fac813f811f6f76a4d90a47f4e Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 6 May 2025 13:17:46 +0300 Subject: [PATCH 10/17] Issuer: Remove from_trust_config() This is not a very useful helper: just use the url at callsite Signed-off-by: Jussi Kukkonen --- sigstore/_cli.py | 2 +- sigstore/oidc.py | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/sigstore/_cli.py b/sigstore/_cli.py index 3554100ea..074776104 100644 --- a/sigstore/_cli.py +++ b/sigstore/_cli.py @@ -1190,7 +1190,7 @@ def _get_identity( if args.oidc_issuer is not None: issuer = Issuer(args.oidc_issuer) else: - issuer = Issuer.from_trust_config(trust_config) + issuer = Issuer(trust_config.signing_config.get_oidc_url()) if args.oidc_client_secret is None: args.oidc_client_secret = "" # nosec: B105 diff --git a/sigstore/oidc.py b/sigstore/oidc.py index c65fb8514..414bf715b 100644 --- a/sigstore/oidc.py +++ b/sigstore/oidc.py @@ -32,7 +32,6 @@ from pydantic import BaseModel, StrictStr from sigstore._internal import USER_AGENT -from sigstore._internal.trust import ClientTrustConfig from sigstore.errors import Error, NetworkError # See: https://github.com/sigstore/fulcio/blob/b2186c0/pkg/config/config.go#L182-L201 @@ -269,13 +268,6 @@ def __init__(self, base_url: str) -> None: except ValueError as exc: raise IssuerError(f"OIDC issuer returned invalid configuration: {exc}") - @classmethod - def from_trust_config(cls, trust_config: ClientTrustConfig) -> Issuer: - """ - Return `Issuer` for given `ClientTrustConfig`. - """ - return cls(trust_config.signing_config.get_oidc_url()) - def identity_token( # nosec: B107 self, client_id: str = "sigstore", From a71f38726dbe8627812b4eb48a61dde6262deb1a Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Fri, 9 May 2025 19:46:54 +0300 Subject: [PATCH 11/17] tests: Fake datetime.now() when using mock staging The current staging TUF assets expire in 3 days: mock datetime.now() so they seem valid in the tests. This is absolutely quite sketchy but seems to work. Signed-off-by: Jussi Kukkonen --- test/unit/conftest.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/unit/conftest.py b/test/unit/conftest.py index 4d1b2331c..6f3506820 100644 --- a/test/unit/conftest.py +++ b/test/unit/conftest.py @@ -15,6 +15,7 @@ from __future__ import annotations import base64 +import datetime import os import re from collections import defaultdict @@ -158,6 +159,16 @@ def _fetch(self, url: str) -> Iterator[bytes]: monkeypatch.setattr(updater, "Urllib3Fetcher", lambda app_user_agent: MockFetcher()) + # Using the staging TUF assets is a nice way to test but staging tuf assets expire in + # 3 days so faking now() becomes necessary. This correctly affects checks in + # _internal/trust.py as well + class mydatetime(datetime.datetime): + @classmethod + def now(cls, tz=None): + return datetime.datetime(2025, 5, 6, 0, 0, 0, 0, datetime.timezone.utc) + + monkeypatch.setattr(datetime, "datetime", mydatetime) + return success, failure From 96fc3b69cef1ca755584cd54e50ecc334b170fe9 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 13 May 2025 10:50:38 +0300 Subject: [PATCH 12/17] tests: Add explanation to oidc failure Signed-off-by: Jussi Kukkonen --- test/unit/internal/oidc/test_issuer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/internal/oidc/test_issuer.py b/test/unit/internal/oidc/test_issuer.py index fc2ae873d..629071f11 100644 --- a/test/unit/internal/oidc/test_issuer.py +++ b/test/unit/internal/oidc/test_issuer.py @@ -30,7 +30,7 @@ def test_init_url(): @pytest.mark.online def test_get_identity_token_bad_code(monkeypatch): + # Send token request to oauth2.sigstage.dev but provide a bogus authorization code monkeypatch.setattr("builtins.input", lambda _: "hunter2") - with pytest.raises(IdentityError, match=r"^Token request failed with .+$"): Issuer("https://oauth2.sigstage.dev/auth").identity_token(force_oob=True) From 1d45514381cf09f22d6800406aa6b42a31410bdf Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 13 May 2025 16:06:24 +0300 Subject: [PATCH 13/17] CHANGELOG: List all API changes WRT trust config * Also fix some typos in other changelog entries and remove "API" from the rekor trailing slash change (it's not actually a sigstore-python API change) Signed-off-by: Jussi Kukkonen --- CHANGELOG.md | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fcff70c5..e5c116e75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,19 +13,34 @@ All versions prior to 0.9.0 are untracked. * TSA: Changed the Timestamp Authority requests to explicitly use sha256 for message digests. [#1373](https://github.com/sigstore/sigstore-python/pull/1373) -* Fixed the certificate calidity period check for Timestamp Authorities (TSA). - Certificates need not have and end date, while still requiring a start date. +* Fixed the certificate validity period check for Timestamp Authorities (TSA). + Certificates need not have an end date, while still requiring a start date. [#1368](https://github.com/sigstore/sigstore-python/pull/1368) -* API: Make Rekor APIs compatible with Rekor v2 by removing trailing slashes +* Made Rekor client more compatible with Rekor v2 by removing trailing slashes from endpoints ([#1366](https://github.com/sigstore/sigstore-python/pull/1366)) ### Changed +* API: + * ClientTrustConfig now provides methods `production()`, `staging()`and `from_tuf()` + to get access to current client configuration (trusted keys & certificates, + URLs and their validity periods). [#1363](https://github.com/sigstore/sigstore-python/pull/1363) * `--trust-config` now requires a file with SigningConfig v0.2, and is able to fully configure the used Sigstore instance [#1358]/(https://github.com/sigstore/sigstore-python/pull/1358) -* By default (when `--trust-config` is not used) signing configuration now comes from - the TUF repository just like the trust root +* By default (when `--trust-config` is not used) the whole trust configuration now + comes from the TUF repository [#1363](https://github.com/sigstore/sigstore-python/pull/1363) + +### Removed + * API: + * `Issuer.production()` and `Issuer.staging()` have been removed: Use + `Issuer()` instead with relevant URL. The current public good production and + staging URLs are available via the `ClientTrustConfig` object. + [#1363](https://github.com/sigstore/sigstore-python/pull/1363) + * `Signingcontext.production()` and `Signingcontext.staging()` have been removed: + Use `Signingcontext.from_trust_config()` instead. + [#1363](https://github.com/sigstore/sigstore-python/pull/1363) + ## [3.6.2] From 2236d977efc3c06b4b2a0a7dc52470ecf6606f44 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Fri, 16 May 2025 10:18:01 +0300 Subject: [PATCH 14/17] ClientTrustConfig: Add comment with bug link Signed-off-by: Jussi Kukkonen --- sigstore/_internal/trust.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sigstore/_internal/trust.py b/sigstore/_internal/trust.py index 1a663a603..f77181ef0 100644 --- a/sigstore/_internal/trust.py +++ b/sigstore/_internal/trust.py @@ -581,6 +581,7 @@ def from_tuf( inner_sc = _SigningConfig().from_json(Path(sc_path).read_bytes()) except TUFError as e: # TUF repo may not have signing config yet: hard code values for prod: + # https://github.com/sigstore/sigstore-python/issues/1388 if url == DEFAULT_TUF_URL: embedded = read_embedded("signing_config.v0.2.json", url) inner_sc = _SigningConfig().from_json(embedded) From 99b4f6dae5063e141ec3a002d520e29d56d1c139 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Fri, 16 May 2025 10:21:03 +0300 Subject: [PATCH 15/17] Makefile: Update sigstore/_store/ paths The repository name is now based on the url Signed-off-by: Jussi Kukkonen --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 23ddb2cec..c7945f307 100644 --- a/Makefile +++ b/Makefile @@ -177,6 +177,6 @@ update-embedded-root: $(VENV)/pyvenv.cfg . $(VENV_BIN)/activate && \ python -m sigstore plumbing update-trust-root cp ~/.local/share/sigstore-python/tuf/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/root.json \ - sigstore/_store/prod/root.json + sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/root.json cp ~/.cache/sigstore-python/tuf/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/trusted_root.json \ - sigstore/_store/prod/trusted_root.json + sigstore/_store/https%3A%2F%2Ftuf-repo-cdn.sigstore.dev/trusted_root.json From 8321ada226d4810a92ee6232ef95c1f66136c1c8 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Fri, 16 May 2025 10:23:43 +0300 Subject: [PATCH 16/17] cli: Refactor --offline parsing Signed-off-by: Jussi Kukkonen --- sigstore/_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sigstore/_cli.py b/sigstore/_cli.py index 074776104..5846fe753 100644 --- a/sigstore/_cli.py +++ b/sigstore/_cli.py @@ -1165,8 +1165,8 @@ def _get_trust_config(args: argparse.Namespace) -> ClientTrustConfig: The configuration may come from explicit argument (--trust-config) or from the TUF repository of the used Sigstore instance. """ - # Some commands do not have offline argument, parse carefully - offline = args.offline if "offline" in args else False + # Not all commands provide --offline + offline = getattr(args, "offline", False) if args.trust_config: return ClientTrustConfig.from_json(args.trust_config.read_text()) From 6ee0ba4762323da484c5f098c7498e4c7a9f651f Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Fri, 16 May 2025 10:26:03 +0300 Subject: [PATCH 17/17] CHANGELOG: Fix spelling Signed-off-by: Jussi Kukkonen --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f278d91e..25f95628f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,8 +46,8 @@ All versions prior to 0.9.0 are untracked. `Issuer()` instead with relevant URL. The current public good production and staging URLs are available via the `ClientTrustConfig` object. [#1363](https://github.com/sigstore/sigstore-python/pull/1363) - * `Signingcontext.production()` and `Signingcontext.staging()` have been removed: - Use `Signingcontext.from_trust_config()` instead. + * `SigningContext.production()` and `SigningContext.staging()` have been removed: + Use `SigningContext.from_trust_config()` instead. [#1363](https://github.com/sigstore/sigstore-python/pull/1363)