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 actual_manifest = self._hashing_config.hash(model_path) 101 102 if actual_manifest != expected_manifest: 103 raise ValueError("Signature mismatch") 104 105 def set_hashing_config(self, hashing_config: hashing.Config) -> Self: 106 """Sets the new configuration for hashing models. 107 108 After calling this method, the automatic guessing of the hashing 109 configuration used during signing is no longer possible from within one 110 instance of this class. 111 112 Args: 113 hashing_config: The new hashing configuration. 114 115 Returns: 116 The new signing configuration. 117 """ 118 self._hashing_config = hashing_config 119 return self 120 121 def _guess_hashing_config(self, source_manifest: manifest.Manifest) -> None: 122 """Attempts to guess the hashing config from a manifest.""" 123 args = source_manifest.serialization_type 124 method = args["method"] 125 # TODO: Once Python 3.9 support is deprecated revert to using `match` 126 if method == "files": 127 self._hashing_config = hashing.Config().use_file_serialization( 128 hashing_algorithm=args["hash_type"], 129 allow_symlinks=args["allow_symlinks"], 130 ) 131 elif method == "shards": 132 self._hashing_config = hashing.Config().use_shard_serialization( 133 hashing_algorithm=args["hash_type"], 134 shard_size=args["shard_size"], 135 allow_symlinks=args["allow_symlinks"], 136 ) 137 else: 138 raise ValueError("Cannot guess the hashing configuration") 139 140 def use_sigstore_verifier( 141 self, *, identity: str, oidc_issuer: str, use_staging: bool = False 142 ) -> Self: 143 """Configures the verification of signatures produced by Sigstore. 144 145 The verifier in this configuration is changed to one that performs 146 verification of Sigstore signatures (sigstore bundles signed by 147 keyless signing via Sigstore). 148 149 Args: 150 identity: The expected identity that has signed the model. 151 oidc_issuer: The expected OpenID Connect issuer that provided the 152 certificate used for the signature. 153 use_staging: Use staging configurations, instead of production. This 154 is supposed to be set to True only when testing. Default is False. 155 156 Return: 157 The new verification configuration. 158 """ 159 self._uses_sigstore = True 160 self._verifier = sigstore.Verifier( 161 identity=identity, oidc_issuer=oidc_issuer, use_staging=use_staging 162 ) 163 return self 164 165 def use_elliptic_key_verifier( 166 self, *, public_key: hashing.PathLike 167 ) -> Self: 168 """Configures the verification of signatures generated by a private key. 169 170 The verifier in this configuration is changed to one that performs 171 verification of sgistore bundles signed by an elliptic curve private 172 key. The public key used in the configuration must match the private key 173 used during signing. 174 175 Args: 176 public_key: The path to the public key to verify with. 177 178 Return: 179 The new verification configuration. 180 """ 181 self._uses_sigstore = False 182 self._verifier = ec_key.Verifier(pathlib.Path(public_key)) 183 return self 184 185 def use_certificate_verifier( 186 self, 187 *, 188 certificate_chain: Iterable[hashing.PathLike] = frozenset(), 189 log_fingerprints: bool = False, 190 ) -> Self: 191 """Configures the verification of signatures generated by a certificate. 192 193 The verifier in this configuration is changed to one that performs 194 verification of sgistore bundles signed by a signing certificate. 195 196 Args: 197 certificate_chain: Certificate chain to establish root of trust. If 198 empty, the operating system's one is used. 199 log_fingerprints: Log certificates' SHA256 fingerprints 200 201 Return: 202 The new verification configuration. 203 """ 204 self._uses_sigstore = False 205 self._verifier = certificate.Verifier( 206 [pathlib.Path(c) for c in certificate_chain], 207 log_fingerprints=log_fingerprints, 208 ) 209 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 actual_manifest = self._hashing_config.hash(model_path) 102 103 if actual_manifest != expected_manifest: 104 raise ValueError("Signature mismatch") 105 106 def set_hashing_config(self, hashing_config: hashing.Config) -> Self: 107 """Sets the new configuration for hashing models. 108 109 After calling this method, the automatic guessing of the hashing 110 configuration used during signing is no longer possible from within one 111 instance of this class. 112 113 Args: 114 hashing_config: The new hashing configuration. 115 116 Returns: 117 The new signing configuration. 118 """ 119 self._hashing_config = hashing_config 120 return self 121 122 def _guess_hashing_config(self, source_manifest: manifest.Manifest) -> None: 123 """Attempts to guess the hashing config from a manifest.""" 124 args = source_manifest.serialization_type 125 method = args["method"] 126 # TODO: Once Python 3.9 support is deprecated revert to using `match` 127 if method == "files": 128 self._hashing_config = hashing.Config().use_file_serialization( 129 hashing_algorithm=args["hash_type"], 130 allow_symlinks=args["allow_symlinks"], 131 ) 132 elif method == "shards": 133 self._hashing_config = hashing.Config().use_shard_serialization( 134 hashing_algorithm=args["hash_type"], 135 shard_size=args["shard_size"], 136 allow_symlinks=args["allow_symlinks"], 137 ) 138 else: 139 raise ValueError("Cannot guess the hashing configuration") 140 141 def use_sigstore_verifier( 142 self, *, identity: str, oidc_issuer: str, use_staging: bool = False 143 ) -> Self: 144 """Configures the verification of signatures produced by Sigstore. 145 146 The verifier in this configuration is changed to one that performs 147 verification of Sigstore signatures (sigstore bundles signed by 148 keyless signing via Sigstore). 149 150 Args: 151 identity: The expected identity that has signed the model. 152 oidc_issuer: The expected OpenID Connect issuer that provided the 153 certificate used for the signature. 154 use_staging: Use staging configurations, instead of production. This 155 is supposed to be set to True only when testing. Default is False. 156 157 Return: 158 The new verification configuration. 159 """ 160 self._uses_sigstore = True 161 self._verifier = sigstore.Verifier( 162 identity=identity, oidc_issuer=oidc_issuer, use_staging=use_staging 163 ) 164 return self 165 166 def use_elliptic_key_verifier( 167 self, *, public_key: hashing.PathLike 168 ) -> Self: 169 """Configures the verification of signatures generated by a private key. 170 171 The verifier in this configuration is changed to one that performs 172 verification of sgistore bundles signed by an elliptic curve private 173 key. The public key used in the configuration must match the private key 174 used during signing. 175 176 Args: 177 public_key: The path to the public key to verify with. 178 179 Return: 180 The new verification configuration. 181 """ 182 self._uses_sigstore = False 183 self._verifier = ec_key.Verifier(pathlib.Path(public_key)) 184 return self 185 186 def use_certificate_verifier( 187 self, 188 *, 189 certificate_chain: Iterable[hashing.PathLike] = frozenset(), 190 log_fingerprints: bool = False, 191 ) -> Self: 192 """Configures the verification of signatures generated by a certificate. 193 194 The verifier in this configuration is changed to one that performs 195 verification of sgistore bundles signed by a signing certificate. 196 197 Args: 198 certificate_chain: Certificate chain to establish root of trust. If 199 empty, the operating system's one is used. 200 log_fingerprints: Log certificates' SHA256 fingerprints 201 202 Return: 203 The new verification configuration. 204 """ 205 self._uses_sigstore = False 206 self._verifier = certificate.Verifier( 207 [pathlib.Path(c) for c in certificate_chain], 208 log_fingerprints=log_fingerprints, 209 ) 210 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 actual_manifest = self._hashing_config.hash(model_path) 102 103 if actual_manifest != expected_manifest: 104 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.
106 def set_hashing_config(self, hashing_config: hashing.Config) -> Self: 107 """Sets the new configuration for hashing models. 108 109 After calling this method, the automatic guessing of the hashing 110 configuration used during signing is no longer possible from within one 111 instance of this class. 112 113 Args: 114 hashing_config: The new hashing configuration. 115 116 Returns: 117 The new signing configuration. 118 """ 119 self._hashing_config = hashing_config 120 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.
141 def use_sigstore_verifier( 142 self, *, identity: str, oidc_issuer: str, use_staging: bool = False 143 ) -> Self: 144 """Configures the verification of signatures produced by Sigstore. 145 146 The verifier in this configuration is changed to one that performs 147 verification of Sigstore signatures (sigstore bundles signed by 148 keyless signing via Sigstore). 149 150 Args: 151 identity: The expected identity that has signed the model. 152 oidc_issuer: The expected OpenID Connect issuer that provided the 153 certificate used for the signature. 154 use_staging: Use staging configurations, instead of production. This 155 is supposed to be set to True only when testing. Default is False. 156 157 Return: 158 The new verification configuration. 159 """ 160 self._uses_sigstore = True 161 self._verifier = sigstore.Verifier( 162 identity=identity, oidc_issuer=oidc_issuer, use_staging=use_staging 163 ) 164 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.
166 def use_elliptic_key_verifier( 167 self, *, public_key: hashing.PathLike 168 ) -> Self: 169 """Configures the verification of signatures generated by a private key. 170 171 The verifier in this configuration is changed to one that performs 172 verification of sgistore bundles signed by an elliptic curve private 173 key. The public key used in the configuration must match the private key 174 used during signing. 175 176 Args: 177 public_key: The path to the public key to verify with. 178 179 Return: 180 The new verification configuration. 181 """ 182 self._uses_sigstore = False 183 self._verifier = ec_key.Verifier(pathlib.Path(public_key)) 184 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.
186 def use_certificate_verifier( 187 self, 188 *, 189 certificate_chain: Iterable[hashing.PathLike] = frozenset(), 190 log_fingerprints: bool = False, 191 ) -> Self: 192 """Configures the verification of signatures generated by a certificate. 193 194 The verifier in this configuration is changed to one that performs 195 verification of sgistore bundles signed by a signing certificate. 196 197 Args: 198 certificate_chain: Certificate chain to establish root of trust. If 199 empty, the operating system's one is used. 200 log_fingerprints: Log certificates' SHA256 fingerprints 201 202 Return: 203 The new verification configuration. 204 """ 205 self._uses_sigstore = False 206 self._verifier = certificate.Verifier( 207 [pathlib.Path(c) for c in certificate_chain], 208 log_fingerprints=log_fingerprints, 209 ) 210 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.