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 pathlib 42import sys 43 44from model_signing import hashing 45from model_signing import manifest 46from model_signing._signing import sign_certificate as certificate 47from model_signing._signing import sign_ec_key as ec_key 48from model_signing._signing import sign_sigstore as sigstore 49from model_signing._signing import sign_sigstore_pb as sigstore_pb 50 51 52if sys.version_info >= (3, 11): 53 from typing import Self 54else: 55 from typing_extensions import Self 56 57 58class Config: 59 """Configuration to use when verifying models against signatures. 60 61 The verification configuration is needed to determine how to read and verify 62 the signature. Given we support multiple signing format, the verification 63 settings must match the signing ones. 64 65 The configuration also supports configuring the hashing configuration from 66 `model_signing.hashing`. This should also match the configuration used 67 during signing. However, by default, we can attempt to guess it from the 68 signature. 69 """ 70 71 def __init__(self): 72 """Initializes the default configuration for verification.""" 73 self._hashing_config = None 74 self._verifier = None 75 self._uses_sigstore = False 76 77 def verify( 78 self, model_path: hashing.PathLike, signature_path: hashing.PathLike 79 ): 80 """Verifies that a model conforms to a signature. 81 82 Args: 83 model_path: The path to the model to verify. 84 85 Raises: 86 ValueError: No verifier has been configured. 87 """ 88 if self._verifier is None: 89 raise ValueError("Attempting to verify with no configured verifier") 90 91 if self._uses_sigstore: 92 signature = sigstore.Signature.read(pathlib.Path(signature_path)) 93 else: 94 signature = sigstore_pb.Signature.read(pathlib.Path(signature_path)) 95 96 expected_manifest = self._verifier.verify(signature) 97 98 if self._hashing_config is None: 99 self._guess_hashing_config(expected_manifest) 100 if "ignore_paths" in expected_manifest.serialization_type: 101 self._hashing_config.add_ignored_paths( 102 model_path=model_path, 103 paths=expected_manifest.serialization_type["ignore_paths"], 104 ) 105 actual_manifest = self._hashing_config.hash(model_path) 106 107 if actual_manifest != expected_manifest: 108 raise ValueError("Signature mismatch") 109 110 def set_hashing_config(self, hashing_config: hashing.Config) -> Self: 111 """Sets the new configuration for hashing models. 112 113 After calling this method, the automatic guessing of the hashing 114 configuration used during signing is no longer possible from within one 115 instance of this class. 116 117 Args: 118 hashing_config: The new hashing configuration. 119 120 Returns: 121 The new signing configuration. 122 """ 123 self._hashing_config = hashing_config 124 return self 125 126 def _guess_hashing_config(self, source_manifest: manifest.Manifest) -> None: 127 """Attempts to guess the hashing config from a manifest.""" 128 args = source_manifest.serialization_type 129 method = args["method"] 130 # TODO: Once Python 3.9 support is deprecated revert to using `match` 131 if method == "files": 132 self._hashing_config = hashing.Config().use_file_serialization( 133 hashing_algorithm=args["hash_type"], 134 allow_symlinks=args["allow_symlinks"], 135 ignore_paths=args.get("ignore_paths", frozenset()), 136 ) 137 elif method == "shards": 138 self._hashing_config = hashing.Config().use_shard_serialization( 139 hashing_algorithm=args["hash_type"], 140 shard_size=args["shard_size"], 141 allow_symlinks=args["allow_symlinks"], 142 ignore_paths=args.get("ignore_paths", frozenset()), 143 ) 144 else: 145 raise ValueError("Cannot guess the hashing configuration") 146 147 def use_sigstore_verifier( 148 self, *, identity: str, oidc_issuer: str, use_staging: bool = False 149 ) -> Self: 150 """Configures the verification of signatures produced by Sigstore. 151 152 The verifier in this configuration is changed to one that performs 153 verification of Sigstore signatures (sigstore bundles signed by 154 keyless signing via Sigstore). 155 156 Args: 157 identity: The expected identity that has signed the model. 158 oidc_issuer: The expected OpenID Connect issuer that provided the 159 certificate used for the signature. 160 use_staging: Use staging configurations, instead of production. This 161 is supposed to be set to True only when testing. Default is False. 162 163 Return: 164 The new verification configuration. 165 """ 166 self._uses_sigstore = True 167 self._verifier = sigstore.Verifier( 168 identity=identity, oidc_issuer=oidc_issuer, use_staging=use_staging 169 ) 170 return self 171 172 def use_elliptic_key_verifier( 173 self, *, public_key: hashing.PathLike 174 ) -> Self: 175 """Configures the verification of signatures generated by a private key. 176 177 The verifier in this configuration is changed to one that performs 178 verification of sgistore bundles signed by an elliptic curve private 179 key. The public key used in the configuration must match the private key 180 used during signing. 181 182 Args: 183 public_key: The path to the public key to verify with. 184 185 Return: 186 The new verification configuration. 187 """ 188 self._uses_sigstore = False 189 self._verifier = ec_key.Verifier(pathlib.Path(public_key)) 190 return self 191 192 def use_certificate_verifier( 193 self, 194 *, 195 certificate_chain: Iterable[hashing.PathLike] = frozenset(), 196 log_fingerprints: bool = False, 197 ) -> Self: 198 """Configures the verification of signatures generated by a certificate. 199 200 The verifier in this configuration is changed to one that performs 201 verification of sgistore bundles signed by a signing certificate. 202 203 Args: 204 certificate_chain: Certificate chain to establish root of trust. If 205 empty, the operating system's one is used. 206 log_fingerprints: Log certificates' SHA256 fingerprints 207 208 Return: 209 The new verification configuration. 210 """ 211 self._uses_sigstore = False 212 self._verifier = certificate.Verifier( 213 [pathlib.Path(c) for c in certificate_chain], 214 log_fingerprints=log_fingerprints, 215 ) 216 return self
59class Config: 60 """Configuration to use when verifying models against signatures. 61 62 The verification configuration is needed to determine how to read and verify 63 the signature. Given we support multiple signing format, the verification 64 settings must match the signing ones. 65 66 The configuration also supports configuring the hashing configuration from 67 `model_signing.hashing`. This should also match the configuration used 68 during signing. However, by default, we can attempt to guess it from the 69 signature. 70 """ 71 72 def __init__(self): 73 """Initializes the default configuration for verification.""" 74 self._hashing_config = None 75 self._verifier = None 76 self._uses_sigstore = False 77 78 def verify( 79 self, model_path: hashing.PathLike, signature_path: hashing.PathLike 80 ): 81 """Verifies that a model conforms to a signature. 82 83 Args: 84 model_path: The path to the model to verify. 85 86 Raises: 87 ValueError: No verifier has been configured. 88 """ 89 if self._verifier is None: 90 raise ValueError("Attempting to verify with no configured verifier") 91 92 if self._uses_sigstore: 93 signature = sigstore.Signature.read(pathlib.Path(signature_path)) 94 else: 95 signature = sigstore_pb.Signature.read(pathlib.Path(signature_path)) 96 97 expected_manifest = self._verifier.verify(signature) 98 99 if self._hashing_config is None: 100 self._guess_hashing_config(expected_manifest) 101 if "ignore_paths" in expected_manifest.serialization_type: 102 self._hashing_config.add_ignored_paths( 103 model_path=model_path, 104 paths=expected_manifest.serialization_type["ignore_paths"], 105 ) 106 actual_manifest = self._hashing_config.hash(model_path) 107 108 if actual_manifest != expected_manifest: 109 raise ValueError("Signature mismatch") 110 111 def set_hashing_config(self, hashing_config: hashing.Config) -> Self: 112 """Sets the new configuration for hashing models. 113 114 After calling this method, the automatic guessing of the hashing 115 configuration used during signing is no longer possible from within one 116 instance of this class. 117 118 Args: 119 hashing_config: The new hashing configuration. 120 121 Returns: 122 The new signing configuration. 123 """ 124 self._hashing_config = hashing_config 125 return self 126 127 def _guess_hashing_config(self, source_manifest: manifest.Manifest) -> None: 128 """Attempts to guess the hashing config from a manifest.""" 129 args = source_manifest.serialization_type 130 method = args["method"] 131 # TODO: Once Python 3.9 support is deprecated revert to using `match` 132 if method == "files": 133 self._hashing_config = hashing.Config().use_file_serialization( 134 hashing_algorithm=args["hash_type"], 135 allow_symlinks=args["allow_symlinks"], 136 ignore_paths=args.get("ignore_paths", frozenset()), 137 ) 138 elif method == "shards": 139 self._hashing_config = hashing.Config().use_shard_serialization( 140 hashing_algorithm=args["hash_type"], 141 shard_size=args["shard_size"], 142 allow_symlinks=args["allow_symlinks"], 143 ignore_paths=args.get("ignore_paths", frozenset()), 144 ) 145 else: 146 raise ValueError("Cannot guess the hashing configuration") 147 148 def use_sigstore_verifier( 149 self, *, identity: str, oidc_issuer: str, use_staging: bool = False 150 ) -> Self: 151 """Configures the verification of signatures produced by Sigstore. 152 153 The verifier in this configuration is changed to one that performs 154 verification of Sigstore signatures (sigstore bundles signed by 155 keyless signing via Sigstore). 156 157 Args: 158 identity: The expected identity that has signed the model. 159 oidc_issuer: The expected OpenID Connect issuer that provided the 160 certificate used for the signature. 161 use_staging: Use staging configurations, instead of production. This 162 is supposed to be set to True only when testing. Default is False. 163 164 Return: 165 The new verification configuration. 166 """ 167 self._uses_sigstore = True 168 self._verifier = sigstore.Verifier( 169 identity=identity, oidc_issuer=oidc_issuer, use_staging=use_staging 170 ) 171 return self 172 173 def use_elliptic_key_verifier( 174 self, *, public_key: hashing.PathLike 175 ) -> Self: 176 """Configures the verification of signatures generated by a private key. 177 178 The verifier in this configuration is changed to one that performs 179 verification of sgistore bundles signed by an elliptic curve private 180 key. The public key used in the configuration must match the private key 181 used during signing. 182 183 Args: 184 public_key: The path to the public key to verify with. 185 186 Return: 187 The new verification configuration. 188 """ 189 self._uses_sigstore = False 190 self._verifier = ec_key.Verifier(pathlib.Path(public_key)) 191 return self 192 193 def use_certificate_verifier( 194 self, 195 *, 196 certificate_chain: Iterable[hashing.PathLike] = frozenset(), 197 log_fingerprints: bool = False, 198 ) -> Self: 199 """Configures the verification of signatures generated by a certificate. 200 201 The verifier in this configuration is changed to one that performs 202 verification of sgistore bundles signed by a signing certificate. 203 204 Args: 205 certificate_chain: Certificate chain to establish root of trust. If 206 empty, the operating system's one is used. 207 log_fingerprints: Log certificates' SHA256 fingerprints 208 209 Return: 210 The new verification configuration. 211 """ 212 self._uses_sigstore = False 213 self._verifier = certificate.Verifier( 214 [pathlib.Path(c) for c in certificate_chain], 215 log_fingerprints=log_fingerprints, 216 ) 217 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.
72 def __init__(self): 73 """Initializes the default configuration for verification.""" 74 self._hashing_config = None 75 self._verifier = None 76 self._uses_sigstore = False
Initializes the default configuration for verification.
78 def verify( 79 self, model_path: hashing.PathLike, signature_path: hashing.PathLike 80 ): 81 """Verifies that a model conforms to a signature. 82 83 Args: 84 model_path: The path to the model to verify. 85 86 Raises: 87 ValueError: No verifier has been configured. 88 """ 89 if self._verifier is None: 90 raise ValueError("Attempting to verify with no configured verifier") 91 92 if self._uses_sigstore: 93 signature = sigstore.Signature.read(pathlib.Path(signature_path)) 94 else: 95 signature = sigstore_pb.Signature.read(pathlib.Path(signature_path)) 96 97 expected_manifest = self._verifier.verify(signature) 98 99 if self._hashing_config is None: 100 self._guess_hashing_config(expected_manifest) 101 if "ignore_paths" in expected_manifest.serialization_type: 102 self._hashing_config.add_ignored_paths( 103 model_path=model_path, 104 paths=expected_manifest.serialization_type["ignore_paths"], 105 ) 106 actual_manifest = self._hashing_config.hash(model_path) 107 108 if actual_manifest != expected_manifest: 109 raise ValueError("Signature mismatch")
Verifies that a model conforms to a signature.
Arguments:
- model_path: The path to the model to verify.
Raises:
- ValueError: No verifier has been configured.
111 def set_hashing_config(self, hashing_config: hashing.Config) -> Self: 112 """Sets the new configuration for hashing models. 113 114 After calling this method, the automatic guessing of the hashing 115 configuration used during signing is no longer possible from within one 116 instance of this class. 117 118 Args: 119 hashing_config: The new hashing configuration. 120 121 Returns: 122 The new signing configuration. 123 """ 124 self._hashing_config = hashing_config 125 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.
148 def use_sigstore_verifier( 149 self, *, identity: str, oidc_issuer: str, use_staging: bool = False 150 ) -> Self: 151 """Configures the verification of signatures produced by Sigstore. 152 153 The verifier in this configuration is changed to one that performs 154 verification of Sigstore signatures (sigstore bundles signed by 155 keyless signing via Sigstore). 156 157 Args: 158 identity: The expected identity that has signed the model. 159 oidc_issuer: The expected OpenID Connect issuer that provided the 160 certificate used for the signature. 161 use_staging: Use staging configurations, instead of production. This 162 is supposed to be set to True only when testing. Default is False. 163 164 Return: 165 The new verification configuration. 166 """ 167 self._uses_sigstore = True 168 self._verifier = sigstore.Verifier( 169 identity=identity, oidc_issuer=oidc_issuer, use_staging=use_staging 170 ) 171 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.
Return:
The new verification configuration.
173 def use_elliptic_key_verifier( 174 self, *, public_key: hashing.PathLike 175 ) -> Self: 176 """Configures the verification of signatures generated by a private key. 177 178 The verifier in this configuration is changed to one that performs 179 verification of sgistore bundles signed by an elliptic curve private 180 key. The public key used in the configuration must match the private key 181 used during signing. 182 183 Args: 184 public_key: The path to the public key to verify with. 185 186 Return: 187 The new verification configuration. 188 """ 189 self._uses_sigstore = False 190 self._verifier = ec_key.Verifier(pathlib.Path(public_key)) 191 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 sgistore 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.
Return:
The new verification configuration.
193 def use_certificate_verifier( 194 self, 195 *, 196 certificate_chain: Iterable[hashing.PathLike] = frozenset(), 197 log_fingerprints: bool = False, 198 ) -> Self: 199 """Configures the verification of signatures generated by a certificate. 200 201 The verifier in this configuration is changed to one that performs 202 verification of sgistore bundles signed by a signing certificate. 203 204 Args: 205 certificate_chain: Certificate chain to establish root of trust. If 206 empty, the operating system's one is used. 207 log_fingerprints: Log certificates' SHA256 fingerprints 208 209 Return: 210 The new verification configuration. 211 """ 212 self._uses_sigstore = False 213 self._verifier = certificate.Verifier( 214 [pathlib.Path(c) for c in certificate_chain], 215 log_fingerprints=log_fingerprints, 216 ) 217 return self
Configures the verification of signatures generated by a certificate.
The verifier in this configuration is changed to one that performs verification of sgistore 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
Return:
The new verification configuration.