model_signing.verifying
High level API for the verification interface of model_signing library.
This module supports configuring the verification method used to verify a model, before performing the verification.
model_signing.verifying.Config().use_sigstore_verifier(
identity=identity, oidc_issuer=oidc_provider
).verify("finbert", "finbert.sig")
The same verification configuration can be used to verify multiple models:
verifying_config = model_signing.signing.Config().use_elliptic_key_verifier(
public_key="key.pub"
)
for model in all_models:
verifying_config.verify(model, f"{model}_sharded.sig")
The API defined here is stable and backwards compatible.
1# Copyright 2024 The Sigstore Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""High level API for the verification interface of `model_signing` library. 16 17This module supports configuring the verification method used to verify a model, 18before performing the verification. 19 20```python 21model_signing.verifying.Config().use_sigstore_verifier( 22 identity=identity, oidc_issuer=oidc_provider 23).verify("finbert", "finbert.sig") 24``` 25 26The same verification configuration can be used to verify multiple models: 27 28```python 29verifying_config = model_signing.signing.Config().use_elliptic_key_verifier( 30 public_key="key.pub" 31) 32 33for model in all_models: 34 verifying_config.verify(model, f"{model}_sharded.sig") 35``` 36 37The API defined here is stable and backwards compatible. 38""" 39 40from collections.abc import Iterable 41import copy 42import pathlib 43from typing import Self 44 45from model_signing import hashing 46from model_signing import manifest 47from model_signing._signing import sign_certificate as certificate 48from model_signing._signing import sign_ec_key as ec_key 49from model_signing._signing import sign_sigstore as sigstore 50from model_signing._signing import sign_sigstore_pb as sigstore_pb 51 52 53class Config: 54 """Configuration to use when verifying models against signatures. 55 56 The verification configuration is needed to determine how to read and verify 57 the signature. Given we support multiple signing format, the verification 58 settings must match the signing ones. 59 60 The configuration also supports configuring the hashing configuration from 61 `model_signing.hashing`. This should also match the configuration used 62 during signing. However, by default, we can attempt to guess it from the 63 signature. 64 """ 65 66 def __init__(self): 67 """Initializes the default configuration for verification.""" 68 self._hashing_config = None 69 self._verifier = None 70 self._uses_sigstore = False 71 self._ignore_unsigned_files = False 72 73 def verify( 74 self, model_path: hashing.PathLike, signature_path: hashing.PathLike 75 ): 76 """Verifies that a model conforms to a signature. 77 78 Args: 79 model_path: The path to the model to verify. 80 signature_path: The path to the signature file. 81 82 Raises: 83 ValueError: No verifier has been configured. 84 """ 85 if self._verifier is None: 86 raise ValueError("Attempting to verify with no configured verifier") 87 88 if self._uses_sigstore: 89 signature = sigstore.Signature.read(pathlib.Path(signature_path)) 90 else: 91 signature = sigstore_pb.Signature.read(pathlib.Path(signature_path)) 92 93 expected_manifest = self._verifier.verify(signature) 94 95 if self._hashing_config is not None: 96 # The signed manifest's ignore paths are applied below. Copy the 97 # config so they do not mutate the caller's config or accumulate 98 # into later verify() calls on a reused instance. 99 hashing_config = copy.deepcopy(self._hashing_config) 100 else: 101 hashing_config = self._guess_hashing_config(expected_manifest) 102 # OMS v1.0 6.1.1: "The verifier MUST apply the same allow_symlinks 103 # policy recorded in serialization.allow_symlinks". Every verify 104 # subcommand passes a hashing config built from its own 105 # --allow-symlinks flag, so without this the caller's flag silently 106 # replaced the signed policy and _guess_hashing_config, which does read 107 # it, never ran (issue #666). 108 recorded_allow_symlinks = expected_manifest.serialization_type.get( 109 "allow_symlinks" 110 ) 111 if recorded_allow_symlinks is not None: 112 hashing_config.set_allow_symlinks(recorded_allow_symlinks) 113 114 if "ignore_paths" in expected_manifest.serialization_type: 115 hashing_config.add_ignored_paths( 116 model_path=model_path, 117 paths=expected_manifest.serialization_type["ignore_paths"], 118 ) 119 120 if self._ignore_unsigned_files: 121 files_to_hash = [ 122 model_path / rd.identifier 123 for rd in expected_manifest.resource_descriptors() 124 ] 125 else: 126 files_to_hash = None 127 128 actual_manifest = hashing_config.hash( 129 model_path, files_to_hash=files_to_hash 130 ) 131 132 if actual_manifest != expected_manifest: 133 diff_message = self._get_manifest_diff( 134 actual_manifest, expected_manifest 135 ) 136 raise ValueError(f"Signature mismatch: {diff_message}") 137 138 def _get_manifest_diff(self, actual, expected) -> list[str]: 139 diffs = [] 140 141 actual_hashes = { 142 rd.identifier: rd.digest for rd in actual.resource_descriptors() 143 } 144 expected_hashes = { 145 rd.identifier: rd.digest for rd in expected.resource_descriptors() 146 } 147 148 extra_actual_files = set(actual_hashes.keys()) - set( 149 expected_hashes.keys() 150 ) 151 if extra_actual_files: 152 diffs.append( 153 f"Extra files found in model '{actual.model_name}': " 154 f"{', '.join(sorted(extra_actual_files))}" 155 ) 156 157 missing_actual_files = set(expected_hashes.keys()) - set( 158 actual_hashes.keys() 159 ) 160 if missing_actual_files: 161 diffs.append( 162 f"Missing files in model '{actual.model_name}': " 163 f"{', '.join(sorted(missing_actual_files))}" 164 ) 165 166 common_files = set(actual_hashes.keys()) & set(expected_hashes.keys()) 167 for identifier in sorted(common_files): 168 if actual_hashes[identifier] != expected_hashes[identifier]: 169 diffs.append( 170 f"Hash mismatch for '{identifier}': " 171 f"Expected '{expected_hashes[identifier]}', " 172 f"Actual '{actual_hashes[identifier]}'" 173 ) 174 return diffs 175 176 def set_hashing_config(self, hashing_config: hashing.Config) -> Self: 177 """Sets the new configuration for hashing models. 178 179 After calling this method, the automatic guessing of the hashing 180 configuration used during signing is no longer possible from within one 181 instance of this class. 182 183 Args: 184 hashing_config: The new hashing configuration. 185 186 Returns: 187 The new signing configuration. 188 """ 189 self._hashing_config = hashing_config 190 return self 191 192 def set_ignore_unsigned_files(self, ignore_unsigned_files: bool) -> Self: 193 """Sets whether files that were not signed are to be ignored. 194 195 This method allows to ignore those files that are not part of the 196 manifest and therefor were not originally signed. 197 198 Args: 199 ignore_unsigned_files: whether to ignore unsigned files 200 """ 201 self._ignore_unsigned_files = ignore_unsigned_files 202 return self 203 204 def _guess_hashing_config( 205 self, source_manifest: manifest.Manifest 206 ) -> hashing.Config: 207 """Attempts to guess the hashing config from a manifest.""" 208 args = source_manifest.serialization_type 209 method = args["method"] 210 match method: 211 case "files": 212 return hashing.Config().use_file_serialization( 213 hashing_algorithm=args["hash_type"], 214 allow_symlinks=args["allow_symlinks"], 215 ignore_paths=args.get("ignore_paths", frozenset()), 216 ) 217 case "shards": 218 return hashing.Config().use_shard_serialization( 219 hashing_algorithm=args["hash_type"], 220 shard_size=args["shard_size"], 221 allow_symlinks=args["allow_symlinks"], 222 ignore_paths=args.get("ignore_paths", frozenset()), 223 ) 224 case _: 225 raise ValueError("Cannot guess the hashing configuration") 226 227 def use_sigstore_verifier( 228 self, 229 *, 230 identity: str, 231 oidc_issuer: str, 232 use_staging: bool = False, 233 trust_config: pathlib.Path | None = None, 234 ) -> Self: 235 """Configures the verification of signatures produced by Sigstore. 236 237 The verifier in this configuration is changed to one that performs 238 verification of Sigstore signatures (sigstore bundles signed by 239 keyless signing via Sigstore). 240 241 Args: 242 identity: The expected identity that has signed the model. 243 oidc_issuer: The expected OpenID Connect issuer that provided the 244 certificate used for the signature. 245 use_staging: Use staging configurations, instead of production. This 246 is supposed to be set to True only when testing. Default is False. 247 trust_config: A path to a custom trust configuration. When provided, 248 the signature verification process will rely on the supplied 249 PKI and trust configurations, instead of the default Sigstore 250 setup. If not specified, the default Sigstore configuration 251 is used. 252 253 Return: 254 The new verification configuration. 255 """ 256 self._uses_sigstore = True 257 self._verifier = sigstore.Verifier( 258 identity=identity, 259 oidc_issuer=oidc_issuer, 260 use_staging=use_staging, 261 trust_config=trust_config, 262 ) 263 return self 264 265 def use_elliptic_key_verifier( 266 self, 267 *, 268 public_key: hashing.PathLike, 269 trust_config: hashing.PathLike | None = None, 270 require_timestamp: bool = False, 271 ) -> Self: 272 """Configures the verification of signatures generated by a private key. 273 274 The verifier in this configuration is changed to one that performs 275 verification of sigstore bundles signed by an elliptic curve private 276 key. The public key used in the configuration must match the private key 277 used during signing. 278 279 Args: 280 public_key: The path to the public key to verify with. 281 trust_config: A Sigstore client trust configuration or trusted root 282 used to verify timestamps. If omitted, Sigstore production trust 283 is used. 284 require_timestamp: Reject signatures without an RFC 3161 timestamp. 285 286 Return: 287 The new verification configuration. 288 """ 289 self._uses_sigstore = False 290 self._verifier = ec_key.Verifier( 291 pathlib.Path(public_key), 292 pathlib.Path(trust_config) if trust_config else None, 293 require_timestamp=require_timestamp, 294 ) 295 return self 296 297 def use_certificate_verifier( 298 self, 299 *, 300 certificate_chain: Iterable[hashing.PathLike] = frozenset(), 301 log_fingerprints: bool = False, 302 expected_san_uris: Iterable[str] = frozenset(), 303 trust_config: hashing.PathLike | None = None, 304 require_timestamp: bool = False, 305 ) -> Self: 306 """Configures the verification of signatures generated by a certificate. 307 308 The verifier in this configuration is changed to one that performs 309 verification of sigstore bundles signed by a signing certificate. 310 311 Args: 312 certificate_chain: Certificate chain to establish root of trust. If 313 empty, the operating system's one is used. 314 log_fingerprints: Log certificates' SHA256 fingerprints 315 expected_san_uris: Optional URIs that must appear in the leaf 316 certificate's SubjectAltName. Binds the signature to a specific 317 signer identity (e.g. a SPIFFE ID) in addition to 318 chain-of-trust. 319 trust_config: A Sigstore client trust configuration or trusted root 320 used to verify timestamps. If omitted, Sigstore production trust 321 is used. 322 require_timestamp: Reject signatures without an RFC 3161 timestamp. 323 324 Return: 325 The new verification configuration. 326 """ 327 self._uses_sigstore = False 328 self._verifier = certificate.Verifier( 329 [pathlib.Path(c) for c in certificate_chain], 330 log_fingerprints=log_fingerprints, 331 expected_san_uris=expected_san_uris, 332 trust_config=pathlib.Path(trust_config) if trust_config else None, 333 require_timestamp=require_timestamp, 334 ) 335 return self
54class Config: 55 """Configuration to use when verifying models against signatures. 56 57 The verification configuration is needed to determine how to read and verify 58 the signature. Given we support multiple signing format, the verification 59 settings must match the signing ones. 60 61 The configuration also supports configuring the hashing configuration from 62 `model_signing.hashing`. This should also match the configuration used 63 during signing. However, by default, we can attempt to guess it from the 64 signature. 65 """ 66 67 def __init__(self): 68 """Initializes the default configuration for verification.""" 69 self._hashing_config = None 70 self._verifier = None 71 self._uses_sigstore = False 72 self._ignore_unsigned_files = False 73 74 def verify( 75 self, model_path: hashing.PathLike, signature_path: hashing.PathLike 76 ): 77 """Verifies that a model conforms to a signature. 78 79 Args: 80 model_path: The path to the model to verify. 81 signature_path: The path to the signature file. 82 83 Raises: 84 ValueError: No verifier has been configured. 85 """ 86 if self._verifier is None: 87 raise ValueError("Attempting to verify with no configured verifier") 88 89 if self._uses_sigstore: 90 signature = sigstore.Signature.read(pathlib.Path(signature_path)) 91 else: 92 signature = sigstore_pb.Signature.read(pathlib.Path(signature_path)) 93 94 expected_manifest = self._verifier.verify(signature) 95 96 if self._hashing_config is not None: 97 # The signed manifest's ignore paths are applied below. Copy the 98 # config so they do not mutate the caller's config or accumulate 99 # into later verify() calls on a reused instance. 100 hashing_config = copy.deepcopy(self._hashing_config) 101 else: 102 hashing_config = self._guess_hashing_config(expected_manifest) 103 # OMS v1.0 6.1.1: "The verifier MUST apply the same allow_symlinks 104 # policy recorded in serialization.allow_symlinks". Every verify 105 # subcommand passes a hashing config built from its own 106 # --allow-symlinks flag, so without this the caller's flag silently 107 # replaced the signed policy and _guess_hashing_config, which does read 108 # it, never ran (issue #666). 109 recorded_allow_symlinks = expected_manifest.serialization_type.get( 110 "allow_symlinks" 111 ) 112 if recorded_allow_symlinks is not None: 113 hashing_config.set_allow_symlinks(recorded_allow_symlinks) 114 115 if "ignore_paths" in expected_manifest.serialization_type: 116 hashing_config.add_ignored_paths( 117 model_path=model_path, 118 paths=expected_manifest.serialization_type["ignore_paths"], 119 ) 120 121 if self._ignore_unsigned_files: 122 files_to_hash = [ 123 model_path / rd.identifier 124 for rd in expected_manifest.resource_descriptors() 125 ] 126 else: 127 files_to_hash = None 128 129 actual_manifest = hashing_config.hash( 130 model_path, files_to_hash=files_to_hash 131 ) 132 133 if actual_manifest != expected_manifest: 134 diff_message = self._get_manifest_diff( 135 actual_manifest, expected_manifest 136 ) 137 raise ValueError(f"Signature mismatch: {diff_message}") 138 139 def _get_manifest_diff(self, actual, expected) -> list[str]: 140 diffs = [] 141 142 actual_hashes = { 143 rd.identifier: rd.digest for rd in actual.resource_descriptors() 144 } 145 expected_hashes = { 146 rd.identifier: rd.digest for rd in expected.resource_descriptors() 147 } 148 149 extra_actual_files = set(actual_hashes.keys()) - set( 150 expected_hashes.keys() 151 ) 152 if extra_actual_files: 153 diffs.append( 154 f"Extra files found in model '{actual.model_name}': " 155 f"{', '.join(sorted(extra_actual_files))}" 156 ) 157 158 missing_actual_files = set(expected_hashes.keys()) - set( 159 actual_hashes.keys() 160 ) 161 if missing_actual_files: 162 diffs.append( 163 f"Missing files in model '{actual.model_name}': " 164 f"{', '.join(sorted(missing_actual_files))}" 165 ) 166 167 common_files = set(actual_hashes.keys()) & set(expected_hashes.keys()) 168 for identifier in sorted(common_files): 169 if actual_hashes[identifier] != expected_hashes[identifier]: 170 diffs.append( 171 f"Hash mismatch for '{identifier}': " 172 f"Expected '{expected_hashes[identifier]}', " 173 f"Actual '{actual_hashes[identifier]}'" 174 ) 175 return diffs 176 177 def set_hashing_config(self, hashing_config: hashing.Config) -> Self: 178 """Sets the new configuration for hashing models. 179 180 After calling this method, the automatic guessing of the hashing 181 configuration used during signing is no longer possible from within one 182 instance of this class. 183 184 Args: 185 hashing_config: The new hashing configuration. 186 187 Returns: 188 The new signing configuration. 189 """ 190 self._hashing_config = hashing_config 191 return self 192 193 def set_ignore_unsigned_files(self, ignore_unsigned_files: bool) -> Self: 194 """Sets whether files that were not signed are to be ignored. 195 196 This method allows to ignore those files that are not part of the 197 manifest and therefor were not originally signed. 198 199 Args: 200 ignore_unsigned_files: whether to ignore unsigned files 201 """ 202 self._ignore_unsigned_files = ignore_unsigned_files 203 return self 204 205 def _guess_hashing_config( 206 self, source_manifest: manifest.Manifest 207 ) -> hashing.Config: 208 """Attempts to guess the hashing config from a manifest.""" 209 args = source_manifest.serialization_type 210 method = args["method"] 211 match method: 212 case "files": 213 return hashing.Config().use_file_serialization( 214 hashing_algorithm=args["hash_type"], 215 allow_symlinks=args["allow_symlinks"], 216 ignore_paths=args.get("ignore_paths", frozenset()), 217 ) 218 case "shards": 219 return hashing.Config().use_shard_serialization( 220 hashing_algorithm=args["hash_type"], 221 shard_size=args["shard_size"], 222 allow_symlinks=args["allow_symlinks"], 223 ignore_paths=args.get("ignore_paths", frozenset()), 224 ) 225 case _: 226 raise ValueError("Cannot guess the hashing configuration") 227 228 def use_sigstore_verifier( 229 self, 230 *, 231 identity: str, 232 oidc_issuer: str, 233 use_staging: bool = False, 234 trust_config: pathlib.Path | None = None, 235 ) -> Self: 236 """Configures the verification of signatures produced by Sigstore. 237 238 The verifier in this configuration is changed to one that performs 239 verification of Sigstore signatures (sigstore bundles signed by 240 keyless signing via Sigstore). 241 242 Args: 243 identity: The expected identity that has signed the model. 244 oidc_issuer: The expected OpenID Connect issuer that provided the 245 certificate used for the signature. 246 use_staging: Use staging configurations, instead of production. This 247 is supposed to be set to True only when testing. Default is False. 248 trust_config: A path to a custom trust configuration. When provided, 249 the signature verification process will rely on the supplied 250 PKI and trust configurations, instead of the default Sigstore 251 setup. If not specified, the default Sigstore configuration 252 is used. 253 254 Return: 255 The new verification configuration. 256 """ 257 self._uses_sigstore = True 258 self._verifier = sigstore.Verifier( 259 identity=identity, 260 oidc_issuer=oidc_issuer, 261 use_staging=use_staging, 262 trust_config=trust_config, 263 ) 264 return self 265 266 def use_elliptic_key_verifier( 267 self, 268 *, 269 public_key: hashing.PathLike, 270 trust_config: hashing.PathLike | None = None, 271 require_timestamp: bool = False, 272 ) -> Self: 273 """Configures the verification of signatures generated by a private key. 274 275 The verifier in this configuration is changed to one that performs 276 verification of sigstore bundles signed by an elliptic curve private 277 key. The public key used in the configuration must match the private key 278 used during signing. 279 280 Args: 281 public_key: The path to the public key to verify with. 282 trust_config: A Sigstore client trust configuration or trusted root 283 used to verify timestamps. If omitted, Sigstore production trust 284 is used. 285 require_timestamp: Reject signatures without an RFC 3161 timestamp. 286 287 Return: 288 The new verification configuration. 289 """ 290 self._uses_sigstore = False 291 self._verifier = ec_key.Verifier( 292 pathlib.Path(public_key), 293 pathlib.Path(trust_config) if trust_config else None, 294 require_timestamp=require_timestamp, 295 ) 296 return self 297 298 def use_certificate_verifier( 299 self, 300 *, 301 certificate_chain: Iterable[hashing.PathLike] = frozenset(), 302 log_fingerprints: bool = False, 303 expected_san_uris: Iterable[str] = frozenset(), 304 trust_config: hashing.PathLike | None = None, 305 require_timestamp: bool = False, 306 ) -> Self: 307 """Configures the verification of signatures generated by a certificate. 308 309 The verifier in this configuration is changed to one that performs 310 verification of sigstore bundles signed by a signing certificate. 311 312 Args: 313 certificate_chain: Certificate chain to establish root of trust. If 314 empty, the operating system's one is used. 315 log_fingerprints: Log certificates' SHA256 fingerprints 316 expected_san_uris: Optional URIs that must appear in the leaf 317 certificate's SubjectAltName. Binds the signature to a specific 318 signer identity (e.g. a SPIFFE ID) in addition to 319 chain-of-trust. 320 trust_config: A Sigstore client trust configuration or trusted root 321 used to verify timestamps. If omitted, Sigstore production trust 322 is used. 323 require_timestamp: Reject signatures without an RFC 3161 timestamp. 324 325 Return: 326 The new verification configuration. 327 """ 328 self._uses_sigstore = False 329 self._verifier = certificate.Verifier( 330 [pathlib.Path(c) for c in certificate_chain], 331 log_fingerprints=log_fingerprints, 332 expected_san_uris=expected_san_uris, 333 trust_config=pathlib.Path(trust_config) if trust_config else None, 334 require_timestamp=require_timestamp, 335 ) 336 return self
Configuration to use when verifying models against signatures.
The verification configuration is needed to determine how to read and verify the signature. Given we support multiple signing format, the verification settings must match the signing ones.
The configuration also supports configuring the hashing configuration from
model_signing.hashing. This should also match the configuration used
during signing. However, by default, we can attempt to guess it from the
signature.
67 def __init__(self): 68 """Initializes the default configuration for verification.""" 69 self._hashing_config = None 70 self._verifier = None 71 self._uses_sigstore = False 72 self._ignore_unsigned_files = False
Initializes the default configuration for verification.
74 def verify( 75 self, model_path: hashing.PathLike, signature_path: hashing.PathLike 76 ): 77 """Verifies that a model conforms to a signature. 78 79 Args: 80 model_path: The path to the model to verify. 81 signature_path: The path to the signature file. 82 83 Raises: 84 ValueError: No verifier has been configured. 85 """ 86 if self._verifier is None: 87 raise ValueError("Attempting to verify with no configured verifier") 88 89 if self._uses_sigstore: 90 signature = sigstore.Signature.read(pathlib.Path(signature_path)) 91 else: 92 signature = sigstore_pb.Signature.read(pathlib.Path(signature_path)) 93 94 expected_manifest = self._verifier.verify(signature) 95 96 if self._hashing_config is not None: 97 # The signed manifest's ignore paths are applied below. Copy the 98 # config so they do not mutate the caller's config or accumulate 99 # into later verify() calls on a reused instance. 100 hashing_config = copy.deepcopy(self._hashing_config) 101 else: 102 hashing_config = self._guess_hashing_config(expected_manifest) 103 # OMS v1.0 6.1.1: "The verifier MUST apply the same allow_symlinks 104 # policy recorded in serialization.allow_symlinks". Every verify 105 # subcommand passes a hashing config built from its own 106 # --allow-symlinks flag, so without this the caller's flag silently 107 # replaced the signed policy and _guess_hashing_config, which does read 108 # it, never ran (issue #666). 109 recorded_allow_symlinks = expected_manifest.serialization_type.get( 110 "allow_symlinks" 111 ) 112 if recorded_allow_symlinks is not None: 113 hashing_config.set_allow_symlinks(recorded_allow_symlinks) 114 115 if "ignore_paths" in expected_manifest.serialization_type: 116 hashing_config.add_ignored_paths( 117 model_path=model_path, 118 paths=expected_manifest.serialization_type["ignore_paths"], 119 ) 120 121 if self._ignore_unsigned_files: 122 files_to_hash = [ 123 model_path / rd.identifier 124 for rd in expected_manifest.resource_descriptors() 125 ] 126 else: 127 files_to_hash = None 128 129 actual_manifest = hashing_config.hash( 130 model_path, files_to_hash=files_to_hash 131 ) 132 133 if actual_manifest != expected_manifest: 134 diff_message = self._get_manifest_diff( 135 actual_manifest, expected_manifest 136 ) 137 raise ValueError(f"Signature mismatch: {diff_message}")
Verifies that a model conforms to a signature.
Arguments:
- model_path: The path to the model to verify.
- signature_path: The path to the signature file.
Raises:
- ValueError: No verifier has been configured.
177 def set_hashing_config(self, hashing_config: hashing.Config) -> Self: 178 """Sets the new configuration for hashing models. 179 180 After calling this method, the automatic guessing of the hashing 181 configuration used during signing is no longer possible from within one 182 instance of this class. 183 184 Args: 185 hashing_config: The new hashing configuration. 186 187 Returns: 188 The new signing configuration. 189 """ 190 self._hashing_config = hashing_config 191 return self
Sets the new configuration for hashing models.
After calling this method, the automatic guessing of the hashing configuration used during signing is no longer possible from within one instance of this class.
Arguments:
- hashing_config: The new hashing configuration.
Returns:
The new signing configuration.
193 def set_ignore_unsigned_files(self, ignore_unsigned_files: bool) -> Self: 194 """Sets whether files that were not signed are to be ignored. 195 196 This method allows to ignore those files that are not part of the 197 manifest and therefor were not originally signed. 198 199 Args: 200 ignore_unsigned_files: whether to ignore unsigned files 201 """ 202 self._ignore_unsigned_files = ignore_unsigned_files 203 return self
Sets whether files that were not signed are to be ignored.
This method allows to ignore those files that are not part of the manifest and therefor were not originally signed.
Arguments:
- ignore_unsigned_files: whether to ignore unsigned files
228 def use_sigstore_verifier( 229 self, 230 *, 231 identity: str, 232 oidc_issuer: str, 233 use_staging: bool = False, 234 trust_config: pathlib.Path | None = None, 235 ) -> Self: 236 """Configures the verification of signatures produced by Sigstore. 237 238 The verifier in this configuration is changed to one that performs 239 verification of Sigstore signatures (sigstore bundles signed by 240 keyless signing via Sigstore). 241 242 Args: 243 identity: The expected identity that has signed the model. 244 oidc_issuer: The expected OpenID Connect issuer that provided the 245 certificate used for the signature. 246 use_staging: Use staging configurations, instead of production. This 247 is supposed to be set to True only when testing. Default is False. 248 trust_config: A path to a custom trust configuration. When provided, 249 the signature verification process will rely on the supplied 250 PKI and trust configurations, instead of the default Sigstore 251 setup. If not specified, the default Sigstore configuration 252 is used. 253 254 Return: 255 The new verification configuration. 256 """ 257 self._uses_sigstore = True 258 self._verifier = sigstore.Verifier( 259 identity=identity, 260 oidc_issuer=oidc_issuer, 261 use_staging=use_staging, 262 trust_config=trust_config, 263 ) 264 return self
Configures the verification of signatures produced by Sigstore.
The verifier in this configuration is changed to one that performs verification of Sigstore signatures (sigstore bundles signed by keyless signing via Sigstore).
Arguments:
- identity: The expected identity that has signed the model.
- oidc_issuer: The expected OpenID Connect issuer that provided the certificate used for the signature.
- use_staging: Use staging configurations, instead of production. This is supposed to be set to True only when testing. Default is False.
- trust_config: A path to a custom trust configuration. When provided, the signature verification process will rely on the supplied PKI and trust configurations, instead of the default Sigstore setup. If not specified, the default Sigstore configuration is used.
Return:
The new verification configuration.
266 def use_elliptic_key_verifier( 267 self, 268 *, 269 public_key: hashing.PathLike, 270 trust_config: hashing.PathLike | None = None, 271 require_timestamp: bool = False, 272 ) -> Self: 273 """Configures the verification of signatures generated by a private key. 274 275 The verifier in this configuration is changed to one that performs 276 verification of sigstore bundles signed by an elliptic curve private 277 key. The public key used in the configuration must match the private key 278 used during signing. 279 280 Args: 281 public_key: The path to the public key to verify with. 282 trust_config: A Sigstore client trust configuration or trusted root 283 used to verify timestamps. If omitted, Sigstore production trust 284 is used. 285 require_timestamp: Reject signatures without an RFC 3161 timestamp. 286 287 Return: 288 The new verification configuration. 289 """ 290 self._uses_sigstore = False 291 self._verifier = ec_key.Verifier( 292 pathlib.Path(public_key), 293 pathlib.Path(trust_config) if trust_config else None, 294 require_timestamp=require_timestamp, 295 ) 296 return self
Configures the verification of signatures generated by a private key.
The verifier in this configuration is changed to one that performs verification of sigstore bundles signed by an elliptic curve private key. The public key used in the configuration must match the private key used during signing.
Arguments:
- public_key: The path to the public key to verify with.
- trust_config: A Sigstore client trust configuration or trusted root used to verify timestamps. If omitted, Sigstore production trust is used.
- require_timestamp: Reject signatures without an RFC 3161 timestamp.
Return:
The new verification configuration.
298 def use_certificate_verifier( 299 self, 300 *, 301 certificate_chain: Iterable[hashing.PathLike] = frozenset(), 302 log_fingerprints: bool = False, 303 expected_san_uris: Iterable[str] = frozenset(), 304 trust_config: hashing.PathLike | None = None, 305 require_timestamp: bool = False, 306 ) -> Self: 307 """Configures the verification of signatures generated by a certificate. 308 309 The verifier in this configuration is changed to one that performs 310 verification of sigstore bundles signed by a signing certificate. 311 312 Args: 313 certificate_chain: Certificate chain to establish root of trust. If 314 empty, the operating system's one is used. 315 log_fingerprints: Log certificates' SHA256 fingerprints 316 expected_san_uris: Optional URIs that must appear in the leaf 317 certificate's SubjectAltName. Binds the signature to a specific 318 signer identity (e.g. a SPIFFE ID) in addition to 319 chain-of-trust. 320 trust_config: A Sigstore client trust configuration or trusted root 321 used to verify timestamps. If omitted, Sigstore production trust 322 is used. 323 require_timestamp: Reject signatures without an RFC 3161 timestamp. 324 325 Return: 326 The new verification configuration. 327 """ 328 self._uses_sigstore = False 329 self._verifier = certificate.Verifier( 330 [pathlib.Path(c) for c in certificate_chain], 331 log_fingerprints=log_fingerprints, 332 expected_san_uris=expected_san_uris, 333 trust_config=pathlib.Path(trust_config) if trust_config else None, 334 require_timestamp=require_timestamp, 335 ) 336 return self
Configures the verification of signatures generated by a certificate.
The verifier in this configuration is changed to one that performs verification of sigstore bundles signed by a signing certificate.
Arguments:
- certificate_chain: Certificate chain to establish root of trust. If empty, the operating system's one is used.
- log_fingerprints: Log certificates' SHA256 fingerprints
- expected_san_uris: Optional URIs that must appear in the leaf certificate's SubjectAltName. Binds the signature to a specific signer identity (e.g. a SPIFFE ID) in addition to chain-of-trust.
- trust_config: A Sigstore client trust configuration or trusted root used to verify timestamps. If omitted, Sigstore production trust is used.
- require_timestamp: Reject signatures without an RFC 3161 timestamp.
Return:
The new verification configuration.