use serde::{Deserialize, Serialize};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum AitpError {
#[error("envelope rejected: {0}")]
Envelope(String),
#[error("identity verification failed: {0}")]
Identity(String),
#[error("manifest error: {0}")]
Manifest(String),
#[error("TCT error: {0}")]
Tct(String),
#[error("delegation error: {0}")]
Delegation(String),
#[error("crypto error: {0}")]
Crypto(String),
#[error("AITP error: {0}")]
Other(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[non_exhaustive]
pub enum ErrorCode {
InvalidEnvelope,
InvalidSignature,
ReplayDetected,
TimestampExpired,
UnknownVersion,
TokenAlgMismatch,
TokenTypMismatch,
IdentityFailed,
ManifestExpired,
ManifestSignatureInvalid,
ManifestPopFailed,
ManifestVersionUnknown,
TrustFailed,
PolicyViolation,
KeyResolutionFailed,
IncompatibleTrustAnchors,
PopVerificationFailed,
NonceMismatch,
AudienceMismatch,
GrantOverflow,
InsufficientGrants,
HandshakeModeUnsupported,
TctExpired,
PopChallengeInvalid,
PopResponseInvalid,
DelegationAudienceMismatch,
DelegationScopeExceeded,
DelegationInvalidVoucher,
DelegationSourceTctRevoked,
DelegationInvalidSignature,
DelegationExpired,
DelegationPopFailed,
DelegationMultihopNotSupported,
DelegationHopLimitExceeded,
DelegationChainHashMismatch,
ManifestNotFound,
TctSignatureInvalid,
TctRevoked,
TctExpiresAfterManifest,
BundleInvalidSignature,
BundleVersionMismatch,
BundleExpired,
BundleExpiryWindowInvariant,
BundleCoordinatorIssuerMismatch,
BundleAudienceMismatch,
BundleEmptyParticipants,
BundleParticipantTctInvalid,
BundleNotMember,
SessionBundleInvalid,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pinned_wire_strings() {
let cases: &[(ErrorCode, &str)] = &[
(ErrorCode::AudienceMismatch, "AUDIENCE_MISMATCH"),
(ErrorCode::TctExpired, "TCT_EXPIRED"),
(
ErrorCode::ManifestSignatureInvalid,
"MANIFEST_SIGNATURE_INVALID",
),
(ErrorCode::ReplayDetected, "REPLAY_DETECTED"),
(
ErrorCode::DelegationSourceTctRevoked,
"DELEGATION_SOURCE_TCT_REVOKED",
),
(ErrorCode::InvalidEnvelope, "INVALID_ENVELOPE"),
(ErrorCode::InvalidSignature, "INVALID_SIGNATURE"),
(ErrorCode::TimestampExpired, "TIMESTAMP_EXPIRED"),
(ErrorCode::UnknownVersion, "UNKNOWN_VERSION"),
(ErrorCode::TokenAlgMismatch, "TOKEN_ALG_MISMATCH"),
(ErrorCode::TokenTypMismatch, "TOKEN_TYP_MISMATCH"),
(ErrorCode::IdentityFailed, "IDENTITY_FAILED"),
(ErrorCode::PolicyViolation, "POLICY_VIOLATION"),
(ErrorCode::GrantOverflow, "GRANT_OVERFLOW"),
(ErrorCode::InsufficientGrants, "INSUFFICIENT_GRANTS"),
(ErrorCode::KeyResolutionFailed, "KEY_RESOLUTION_FAILED"),
(ErrorCode::ManifestExpired, "MANIFEST_EXPIRED"),
(ErrorCode::ManifestPopFailed, "MANIFEST_POP_FAILED"),
(
ErrorCode::ManifestVersionUnknown,
"MANIFEST_VERSION_UNKNOWN",
),
(
ErrorCode::IncompatibleTrustAnchors,
"INCOMPATIBLE_TRUST_ANCHORS",
),
(ErrorCode::PopVerificationFailed, "POP_VERIFICATION_FAILED"),
(ErrorCode::NonceMismatch, "NONCE_MISMATCH"),
(ErrorCode::PopChallengeInvalid, "POP_CHALLENGE_INVALID"),
(ErrorCode::PopResponseInvalid, "POP_RESPONSE_INVALID"),
(
ErrorCode::DelegationAudienceMismatch,
"DELEGATION_AUDIENCE_MISMATCH",
),
(
ErrorCode::DelegationScopeExceeded,
"DELEGATION_SCOPE_EXCEEDED",
),
(
ErrorCode::DelegationInvalidVoucher,
"DELEGATION_INVALID_VOUCHER",
),
(
ErrorCode::DelegationInvalidSignature,
"DELEGATION_INVALID_SIGNATURE",
),
(ErrorCode::DelegationExpired, "DELEGATION_EXPIRED"),
(ErrorCode::DelegationPopFailed, "DELEGATION_POP_FAILED"),
(
ErrorCode::DelegationMultihopNotSupported,
"DELEGATION_MULTIHOP_NOT_SUPPORTED",
),
(
ErrorCode::DelegationHopLimitExceeded,
"DELEGATION_HOP_LIMIT_EXCEEDED",
),
(
ErrorCode::DelegationChainHashMismatch,
"DELEGATION_CHAIN_HASH_MISMATCH",
),
(ErrorCode::ManifestNotFound, "MANIFEST_NOT_FOUND"),
(ErrorCode::TrustFailed, "TRUST_FAILED"),
(
ErrorCode::HandshakeModeUnsupported,
"HANDSHAKE_MODE_UNSUPPORTED",
),
(ErrorCode::TctSignatureInvalid, "TCT_SIGNATURE_INVALID"),
(ErrorCode::TctRevoked, "TCT_REVOKED"),
(
ErrorCode::TctExpiresAfterManifest,
"TCT_EXPIRES_AFTER_MANIFEST",
),
(
ErrorCode::BundleInvalidSignature,
"BUNDLE_INVALID_SIGNATURE",
),
(ErrorCode::BundleVersionMismatch, "BUNDLE_VERSION_MISMATCH"),
(ErrorCode::BundleExpired, "BUNDLE_EXPIRED"),
(
ErrorCode::BundleExpiryWindowInvariant,
"BUNDLE_EXPIRY_WINDOW_INVARIANT",
),
(
ErrorCode::BundleCoordinatorIssuerMismatch,
"BUNDLE_COORDINATOR_ISSUER_MISMATCH",
),
(
ErrorCode::BundleAudienceMismatch,
"BUNDLE_AUDIENCE_MISMATCH",
),
(
ErrorCode::BundleEmptyParticipants,
"BUNDLE_EMPTY_PARTICIPANTS",
),
(
ErrorCode::BundleParticipantTctInvalid,
"BUNDLE_PARTICIPANT_TCT_INVALID",
),
(ErrorCode::BundleNotMember, "BUNDLE_NOT_MEMBER"),
(ErrorCode::SessionBundleInvalid, "SESSION_BUNDLE_INVALID"),
];
for (code, wire) in cases {
let v = serde_json::to_value(code).unwrap();
assert_eq!(v.as_str().unwrap(), *wire, "encode {:?}", code);
let back: ErrorCode = serde_json::from_value(v).unwrap();
assert_eq!(back, *code, "decode {}", wire);
}
}
#[test]
fn round_trip_through_json_string() {
let s = serde_json::to_string(&ErrorCode::PopVerificationFailed).unwrap();
assert_eq!(s, "\"POP_VERIFICATION_FAILED\"");
let back: ErrorCode = serde_json::from_str(&s).unwrap();
assert_eq!(back, ErrorCode::PopVerificationFailed);
}
#[test]
fn rejects_unknown_wire_strings() {
assert!(serde_json::from_str::<ErrorCode>("\"NOT_A_REAL_CODE\"").is_err());
assert!(serde_json::from_str::<ErrorCode>("\"audience_mismatch\"").is_err());
}
}