Skip to content

Commit dddbf4e

Browse files
authored
sct, keyring: specialize errors (#555)
* sct, keyring: specialize errors Signed-off-by: Andrew Pan <a@tny.town> * CHANGELOG: blurb for SCT changes Signed-off-by: Andrew Pan <a@tny.town> * CHANGELOG: add ref to PR Signed-off-by: Andrew Pan <a@tny.town> * Apply suggestions from code review Signed-off-by: Andrew Pan <a@tny.town> --------- Signed-off-by: Andrew Pan <a@tny.town>
1 parent d0bf36a commit dddbf4e

File tree

3 files changed

+65
-14
lines changed

3 files changed

+65
-14
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ All versions prior to 0.9.0 are untracked.
2121
([#535](https://github.com/sigstore/sigstore-python/pull/535))
2222
* Revamped error diagnostics reporting. All errors with diagnostics now implement
2323
`sigstore.errors.Error`.
24+
* Improved diagnostics around Signed Certificate Timestamp verification failures.
25+
([#555](https://github.com/sigstore/sigstore-python/pull/555))
2426

2527
### Fixed
2628

sigstore/_internal/keyring.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ class KeyringLookupError(KeyringError):
4444
pass
4545

4646

47+
class KeyringSignatureError(KeyringError):
48+
"""
49+
Raised when `Keyring.verify()` is passed an invalid signature.
50+
"""
51+
52+
4753
class Keyring:
4854
"""
4955
Represents a set of CT signing keys, each of which is a potentially
@@ -101,4 +107,4 @@ def verify(self, *, key_id: KeyID, signature: bytes, data: bytes) -> None:
101107
# NOTE(ww): Unreachable without API misuse.
102108
raise KeyringError(f"unsupported key type: {key}")
103109
except InvalidSignature as exc:
104-
raise KeyringError("invalid signature") from exc
110+
raise KeyringSignatureError("invalid signature") from exc

sigstore/_internal/sct.py

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@
3232
from cryptography.x509.oid import ExtendedKeyUsageOID
3333

3434
from sigstore._internal.ctfe import CTKeyring
35-
from sigstore._internal.keyring import KeyringError, KeyringLookupError
35+
from sigstore._internal.keyring import (
36+
KeyringError,
37+
KeyringLookupError,
38+
KeyringSignatureError,
39+
)
3640
from sigstore._utils import DERCert, KeyID, key_id
3741
from sigstore.errors import Error
3842

@@ -142,13 +146,34 @@ class InvalidSCTError(Error):
142146

143147
def diagnostics(self) -> str:
144148
"""Returns diagnostics for the error."""
145-
# We specialize this error case, since it usually indicates one of
146-
# two conditions: either the current sigstore client is out-of-date,
147-
# or that the SCT is well-formed but invalid for the current configuration
148-
# (indicating that the user has asked for the wrong instance).
149-
if isinstance(self.__cause__, KeyringLookupError):
150-
return dedent(
151-
f"""
149+
150+
ctx = f"\nContext: {self.__context__}" if self.__context__ else ""
151+
return dedent(
152+
f"""
153+
SCT verification failed.
154+
155+
Additional context:
156+
157+
Message: {str(self)}
158+
"""
159+
+ ctx
160+
)
161+
162+
163+
class InvalidSCTKeyError(InvalidSCTError):
164+
"""
165+
Raised during SCT verification if the SCT can't be validated against the given keyring.
166+
167+
We specialize this error case, since it usually indicates one of
168+
two conditions: either the current sigstore client is out-of-date,
169+
or that the SCT is well-formed but invalid for the current configuration
170+
(indicating that the user has asked for the wrong instance).
171+
"""
172+
173+
def diagnostics(self) -> str:
174+
"""Returns diagnostics for the error."""
175+
return dedent(
176+
f"""
152177
Invalid key ID in SCT: not found in current keyring.
153178
154179
This may be a result of an outdated `sigstore` installation.
@@ -161,9 +186,27 @@ def diagnostics(self) -> str:
161186
162187
{self.__cause__}
163188
"""
164-
)
189+
)
165190

166-
return str(self)
191+
192+
class SCTSignatureError(InvalidSCTError):
193+
"""
194+
Raised during SCT verification if the signature of the SCT is invalid.
195+
"""
196+
197+
def diagnostics(self) -> str:
198+
"""Returns diagnostics for the error."""
199+
return dedent(
200+
f"""
201+
Invalid signature on SCT.
202+
203+
If validating a certificate, the certificate associated with this SCT should not be trusted.
204+
205+
Additional context:
206+
207+
{self.__cause__}
208+
"""
209+
)
167210

168211

169212
def verify_sct(
@@ -214,8 +257,8 @@ def verify_sct(
214257
key_id=KeyID(sct.log_id), signature=sct.signature, data=digitally_signed
215258
)
216259
except KeyringLookupError as exc:
217-
raise InvalidSCTError(
218-
"Invalid key ID in SCT: not found in current keyring"
219-
) from exc
260+
raise InvalidSCTKeyError from exc
261+
except KeyringSignatureError as exc:
262+
raise SCTSignatureError from exc
220263
except KeyringError as exc:
221264
raise InvalidSCTError from exc

0 commit comments

Comments
 (0)