use abscissa::Error;
use prost;
use signatory;
use std::{
any::Any,
error::Error as StdError,
fmt::{self, Display},
io,
};
use tendermint;
use tendermint::amino_types::validate::ValidationError as TmValidationError;
#[cfg(feature = "yubihsm")]
use yubihsm;
#[derive(Debug)]
pub struct KmsError(Error<KmsErrorKind>);
impl KmsError {
pub fn from_panic(msg: &Any) -> Self {
if let Some(e) = msg.downcast_ref::<String>() {
err!(KmsErrorKind::PanicError, e)
} else if let Some(e) = msg.downcast_ref::<&str>() {
err!(KmsErrorKind::PanicError, e)
} else {
err!(KmsErrorKind::PanicError, "unknown cause")
}.into()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
pub enum KmsErrorKind {
#[fail(display = "access denied")]
#[cfg(feature = "yubihsm")]
AccessError,
#[fail(display = "config error")]
ConfigError,
#[fail(display = "internal crash")]
PanicError,
#[fail(display = "cryptographic error")]
CryptoError,
#[fail(display = "invalid key")]
InvalidKey,
#[fail(display = "invalid consensus message")]
InvalidMessageError,
#[fail(display = "I/O error")]
IoError,
#[fail(display = "parse error")]
ParseError,
#[fail(display = "protocol error")]
ProtocolError,
#[fail(display = "signing operation failed")]
SigningError,
#[fail(display = "verification failed")]
VerificationError,
}
impl Display for KmsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<Error<KmsErrorKind>> for KmsError {
fn from(other: Error<KmsErrorKind>) -> Self {
KmsError(other)
}
}
impl From<io::Error> for KmsError {
fn from(other: io::Error) -> Self {
err!(KmsErrorKind::IoError, other).into()
}
}
impl From<prost::DecodeError> for KmsError {
fn from(other: prost::DecodeError) -> Self {
err!(KmsErrorKind::ProtocolError, other).into()
}
}
impl From<prost::EncodeError> for KmsError {
fn from(other: prost::EncodeError) -> Self {
err!(KmsErrorKind::ProtocolError, other).into()
}
}
impl From<signatory::Error> for KmsError {
fn from(other: signatory::Error) -> Self {
let kind = match other.kind() {
signatory::ErrorKind::Io => KmsErrorKind::IoError,
signatory::ErrorKind::KeyInvalid => KmsErrorKind::InvalidKey,
signatory::ErrorKind::ParseError => KmsErrorKind::ParseError,
signatory::ErrorKind::ProviderError => KmsErrorKind::SigningError,
signatory::ErrorKind::SignatureInvalid => KmsErrorKind::VerificationError,
};
Error::new(kind, Some(other.description().to_owned())).into()
}
}
impl From<tendermint::Error> for KmsError {
fn from(other: tendermint::Error) -> Self {
let kind = match other {
tendermint::Error::Crypto => KmsErrorKind::CryptoError,
tendermint::Error::InvalidKey => KmsErrorKind::InvalidKey,
tendermint::Error::Io => KmsErrorKind::IoError,
tendermint::Error::Protocol => KmsErrorKind::ProtocolError,
tendermint::Error::Length
| tendermint::Error::Parse
| tendermint::Error::OutOfRange => KmsErrorKind::ParseError,
tendermint::Error::SignatureInvalid => KmsErrorKind::VerificationError,
};
Error::new(kind, None).into()
}
}
impl From<TmValidationError> for KmsError {
fn from(other: TmValidationError) -> Self {
err!(KmsErrorKind::InvalidMessageError, other).into()
}
}
#[cfg(feature = "yubihsm")]
impl From<yubihsm::connector::ConnectionError> for KmsError {
fn from(other: yubihsm::connector::ConnectionError) -> Self {
use yubihsm::connector::ConnectionErrorKind;
let kind = match other.kind() {
ConnectionErrorKind::AddrInvalid => KmsErrorKind::ConfigError,
ConnectionErrorKind::AccessDenied => KmsErrorKind::AccessError,
ConnectionErrorKind::IoError
| ConnectionErrorKind::ConnectionFailed
| ConnectionErrorKind::DeviceBusyError
| ConnectionErrorKind::RequestError
| ConnectionErrorKind::ResponseError
| ConnectionErrorKind::UsbError => KmsErrorKind::IoError,
};
Error::new(kind, Some(other.description().to_owned())).into()
}
}