Skip to main content

aitp_tct/
error.rs

1//! TCT-specific error type.
2
3/// Errors from TCT issuance and verification.
4#[derive(Debug, thiserror::Error)]
5#[non_exhaustive]
6pub enum TctError {
7    /// Version is not supported by this implementation.
8    #[error("TCT version is not supported")]
9    VersionUnknown,
10    /// Signature did not verify against issuer's public key.
11    #[error("TCT signature is invalid")]
12    SignatureInvalid,
13    /// The verifying key supplied by the caller does not correspond to
14    /// the key embedded in `tct.issuer`. RFC-AITP-0008 §3.3 requires
15    /// verifiers to establish this issuer-key binding before consulting
16    /// any revocation source; without it `tct.issuer` stays
17    /// attacker-controlled even after a valid signature, enabling
18    /// revocation evasion and steering of per-issuer revocation lookups.
19    #[error("TCT issuer does not match the verifying key")]
20    IssuerMismatch,
21    /// `audience` did not equal expected audience or did not equal subject.
22    #[error("TCT audience does not match")]
23    AudienceMismatch,
24    /// `expires_at` is in the past, or `issued_at` is in the future.
25    #[error("TCT has expired or is not yet valid")]
26    Expired,
27    /// `expires_at` exceeds the issuer Manifest's `expires_at`.
28    /// RFC-AITP-0004 §4.3 / RFC-AITP-0005 §9: a peer-issued TCT MUST
29    /// NOT outlive the issuer's published Manifest. Verifiers that
30    /// have resolved the issuer's Manifest MUST reject TCTs whose
31    /// `expires_at` exceeds the Manifest's.
32    #[error("TCT expires_at exceeds issuer Manifest expires_at")]
33    ExpiresAfterManifest,
34    /// `jti` appears in the issuer's deny list.
35    #[error("TCT jti is revoked")]
36    Revoked,
37    /// `grants` is empty (forbidden by RFC-AITP-0004 §4.1).
38    #[error("TCT grants must be non-empty")]
39    EmptyGrants,
40    /// One or more grant strings contain whitespace
41    /// (forbidden by RFC-AITP-0005 §4.2).
42    #[error("TCT grant must not contain whitespace: `{0}`")]
43    GrantWhitespace(String),
44    /// `cnf.jkt` does not equal the RFC 7638 thumbprint of the key
45    /// encoded in the subject AID (RFC-AITP-0005 §3).
46    #[error("TCT cnf.jkt does not match the subject key")]
47    CnfMalformed,
48    /// Decoded JWS payload did not deserialize as the artifact's claims
49    /// object — unknown claim outside `ext`, duplicate claim, missing
50    /// required claim, or a type mismatch (RFC-AITP-0001 §5.4.5 strict
51    /// parsing).
52    #[error("claims malformed: {0}")]
53    ClaimsMalformed(String),
54    /// Builder was missing a required field.
55    #[error("missing required field: {0}")]
56    MissingField(&'static str),
57    /// Canonicalization failed.
58    #[error("canonicalization failed: {0}")]
59    Canonicalization(String),
60    /// PoP nonce echo mismatch (RFC-AITP-0005 §6.2 step 2).
61    #[error("PoP nonce echo mismatch")]
62    PopNonceMismatch,
63    /// PoP signature failed verification.
64    #[error("PoP signature failed")]
65    PopFailed,
66    /// PoP challenge expired.
67    #[error("PoP challenge expired")]
68    PopChallengeExpired,
69    /// PoP response references a different jti than the challenge.
70    #[error("PoP response jti mismatch")]
71    PopJtiMismatch,
72    /// Crypto error.
73    #[error(transparent)]
74    Crypto(#[from] aitp_crypto::CryptoError),
75}