1use base64::DecodeError;
2#[cfg(feature = "webauthn-server")]
3use ring::error::Unspecified;
4use serde_cbor::Error as CborError;
5use serde_json::Error as JsonError;
6use std::{
7    error::Error as StdError,
8    fmt::{Debug, Display, Formatter},
9    io::Error as IoError,
10};
11#[cfg(feature = "webauthn-server")]
12use webpki::Error as WebPkiError;
13
14#[derive(Debug)]
15pub enum CredentialError {
16    RequestType,
17    Challenge,
18    Origin,
19    Rp,
20    UserPresentFlag,
21    UserVerifiedFlag,
22    Extensions,
23    KeyType,
24    CertificateMissing,
25    CertificateNotSupported,
26    AttestationMissing,
27    AttestationNotSupported,
28    Other(String),
29}
30
31#[derive(Debug)]
32pub enum TpmError {
33    AlgorithmNotSupported,
34    AttestationVersionNotSupported,
35    AttestedNamePubAreaMismatch,
36    AttToBeSignedHashAlgorithmInvalid(i64),
37    AttToBeSignedMismatch,
38    AttestationTypeInvalid,
39    CertificateMissing,
40    CertificateParsing,
41    CertificateVersionInvalid,
42    CertificateSubjectInvalid,
43    CertificateExtensionNotCritical,
44    CertificateExtensionRequirementNotMet(String),
45    CertificateRequirementNotMet(String),
46    MagicInvalid,
47    PubAreaHashUnknown(u16),
48    PubAreaMismatch,
49    PublicKeyParametersMismatch(i64),
50    PublicKeyCoordinatesMismatch,
51    SignatureHashInvalid(i64),
52    SignatureValidationFailed,
53    TpmVendorNotFound,
54}
55
56#[derive(Debug)]
57pub enum Error {
58    IoError(IoError),
59    Base64Error(DecodeError),
60    CborError(CborError),
61    JsonError(JsonError),
62    #[cfg(feature = "webauthn-server")]
63    WebPkiError(WebPkiError),
64    #[cfg(feature = "webauthn-server")]
65    RingError(Unspecified),
66    Version,
67    CredentialError(CredentialError),
68    TpmError(TpmError),
69    Other(String),
70}
71
72impl From<DecodeError> for Error {
73    fn from(e: DecodeError) -> Self {
74        Error::Base64Error(e)
75    }
76}
77
78impl From<CborError> for Error {
79    fn from(e: CborError) -> Self {
80        Error::CborError(e)
81    }
82}
83
84impl From<JsonError> for Error {
85    fn from(e: JsonError) -> Self {
86        Error::JsonError(e)
87    }
88}
89
90#[cfg(feature = "webauthn-server")]
91impl From<WebPkiError> for Error {
92    fn from(e: WebPkiError) -> Self {
93        Error::WebPkiError(e)
94    }
95}
96
97#[cfg(feature = "webauthn-server")]
98impl From<Unspecified> for Error {
99    fn from(e: Unspecified) -> Self {
100        Error::RingError(e)
101    }
102}
103
104impl StdError for Error {}
105
106impl Display for CredentialError {
107    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
108        use CredentialError::*;
109        match self {
110            RequestType => write!(f, "Wrong request type"),
111            Challenge => write!(f, "Challenges do not match"),
112            Origin => write!(f, "Wrong origin"),
113            Rp => write!(f, "Wrong rp ID"),
114            UserPresentFlag => write!(f, "Missing user present flag"),
115            UserVerifiedFlag => write!(f, "Missing user verified flag"),
116            Extensions => write!(f, "Extensions should not be present"),
117            KeyType => write!(f, "wrong key type"),
118            CertificateMissing => write!(f, "Certificate is missing"),
119            CertificateNotSupported => write!(f, "Ecdaaa certificate is not supported"),
120            AttestationMissing => write!(f, "Missing attested credential data"),
121            AttestationNotSupported => write!(f, "Attestation format is not supported"),
122            Other(s) => write!(f, "{}", s),
123        }
124    }
125}
126
127impl Display for Error {
128    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
129        use Error::*;
130        match self {
131            IoError(io_e) => std::fmt::Display::fmt(io_e, f),
132            Version => write!(f, "Unsupported version"),
133            CredentialError(ce) => std::fmt::Display::fmt(ce, f),
134            Other(s) => write!(f, "{}", s),
135            Base64Error(e) => std::fmt::Display::fmt(e, f),
136            CborError(cb_e) => std::fmt::Display::fmt(cb_e, f),
137            JsonError(js_e) => std::fmt::Display::fmt(js_e, f),
138            #[cfg(feature = "webauthn-server")]
139            WebPkiError(wp_e) => std::fmt::Display::fmt(wp_e, f),
140            #[cfg(feature = "webauthn-server")]
141            RingError(r_e) => std::fmt::Display::fmt(r_e, f),
142            TpmError(tpm_e) => std::fmt::Display::fmt(tpm_e, f),
143        }
144    }
145}
146
147impl Display for TpmError {
148    fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
149        match self {
150            TpmError::AlgorithmNotSupported => write!(f, "Algorithm not supported"),
151            TpmError::AttestationVersionNotSupported => write!(f, "Attestation version not supported"),
152            TpmError::AttestedNamePubAreaMismatch => write!(f, "Attested name does not match with hash of PubArea"),
153            TpmError::AttToBeSignedHashAlgorithmInvalid(hash) => write!(f, "Invalid hash algorithm for AttToBeSigned: {}", hash),
154            TpmError::AttToBeSignedMismatch => write!(f, "AttToBeSigned does not match with CertInfo.extra_data"),
155            TpmError::AttestationTypeInvalid => write!(f, "Attestation type is invalid"),
156            TpmError::CertificateMissing => write!(f, "Aik certificate is missing"),
157            TpmError::CertificateParsing => write!(f, "Error parsing aik certificate"),
158            TpmError::CertificateVersionInvalid => write!(f, "Certificate version is not supported. Expected v3"),
159            TpmError::CertificateSubjectInvalid => write!(f, "Certificate subject is not empty"),
160            TpmError::CertificateExtensionNotCritical => write!(f, "Certificate extension is not critical"),
161            TpmError::CertificateExtensionRequirementNotMet(ext) => write!(f, "Requirements for {} certificate extension are not met", ext),
162            TpmError::CertificateRequirementNotMet(field) => write!(f, "Requirements for {} certificate field are not met", field),
163            TpmError::MagicInvalid => write!(f, "CertInfo.magic is different then TPM_GENERATED_VALUE"),
164            TpmError::PubAreaHashUnknown(hash) => write!(f, "PubArea's Tpm Algorithm ID {} is not supported", hash),
165            TpmError::PubAreaMismatch => write!(f, "PubArea public key information does not match with CredentialPublicKey"),
166            TpmError::PublicKeyParametersMismatch(alg) => write!(
167                f,
168                "PubArea public key parameters does not match with CredentialPublicKey with algorithm {}",
169                alg
170            ),
171            TpmError::PublicKeyCoordinatesMismatch => {
172                write!(f, "PubArea public key coordinates does not match with EC2 CredentialPublicKey")
173            }
174            TpmError::SignatureHashInvalid(hash) => write!(f, "Signature hash not supported {}", hash),
175            TpmError::SignatureValidationFailed => write!(f, "Signature validation failed"),
176            TpmError::TpmVendorNotFound => write!(f, "TPM Vendor not found"),
177        }
178    }
179}
180
181impl From<IoError> for Error {
182    fn from(e: IoError) -> Self {
183        Error::IoError(e)
184    }
185}