use std::{fmt, error};
use std::error::Error;
use msgs::enums::{ContentType, HandshakeType, AlertDescription};
use webpki;
#[derive(Debug, PartialEq, Clone)]
pub enum TLSError {
InappropriateMessage { expect_types: Vec<ContentType>, got_type: ContentType },
InappropriateHandshakeMessage { expect_types: Vec<HandshakeType>, got_type: HandshakeType },
CorruptMessage,
CorruptMessagePayload(ContentType),
NoCertificatesPresented,
DecryptError,
PeerIncompatibleError(String),
PeerMisbehavedError(String),
AlertReceived(AlertDescription),
WebPKIError(webpki::Error),
General(String)
}
fn join<T: fmt::Debug>(vec: &Vec<T>) -> String {
vec
.iter()
.map(|x| format!("{:?}", x))
.collect::<Vec<String>>()
.join(" or ")
}
impl fmt::Display for TLSError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TLSError::InappropriateMessage { ref expect_types, ref got_type }
=> write!(f, "{}: got {:?} when expecting {}",
self.description(), got_type,
join::<ContentType>(&expect_types)),
TLSError::InappropriateHandshakeMessage { ref expect_types, ref got_type }
=> write!(f, "{}: got {:?} when expecting {}",
self.description(), got_type,
join::<HandshakeType>(&expect_types)),
TLSError::CorruptMessagePayload(ref typ)
=> write!(f, "{} of type {:?}", self.description(), typ),
TLSError::PeerIncompatibleError(ref why) | TLSError::PeerMisbehavedError(ref why)
=> write!(f, "{}: {}", self.description(), why),
TLSError::AlertReceived(ref alert)
=> write!(f, "{}: {:?}", self.description(), alert),
TLSError::WebPKIError(ref err)
=> write!(f, "{}: {:?}", self.description(), err),
TLSError::CorruptMessage
| TLSError::NoCertificatesPresented
| TLSError::DecryptError
=> write!(f, "{}", self.description()),
_ => write!(f, "{}: {:?}", self.description(), self)
}
}
}
impl error::Error for TLSError {
fn description(&self) -> &str {
match *self {
TLSError::InappropriateMessage { .. } => "received unexpected message",
TLSError::InappropriateHandshakeMessage { .. } => "received unexpected handshake message",
TLSError::CorruptMessage => "received corrupt message",
TLSError::CorruptMessagePayload(_) => "received corrupt message",
TLSError::NoCertificatesPresented => "peer sent no certificates",
TLSError::DecryptError => "cannot decrypt peer's message",
TLSError::PeerIncompatibleError(_) => "peer is incompatible",
TLSError::PeerMisbehavedError(_) => "peer misbehaved",
TLSError::AlertReceived(_) => "received fatal alert",
TLSError::WebPKIError(_) => "invalid certificate",
TLSError::General(_) => "unexpected error" }
}
}
#[cfg(test)]
mod tests {
#[test]
fn smoke() {
use super::TLSError;
use std::error::Error;
use msgs::enums::{ContentType, HandshakeType, AlertDescription};
use webpki;
let all = vec![
TLSError::InappropriateMessage {
expect_types: vec![ ContentType::Alert ],
got_type: ContentType::Handshake
},
TLSError::InappropriateHandshakeMessage {
expect_types: vec![ HandshakeType::ClientHello, HandshakeType::Finished ],
got_type: HandshakeType::ServerHello
},
TLSError::CorruptMessage,
TLSError::CorruptMessagePayload(ContentType::Alert),
TLSError::NoCertificatesPresented,
TLSError::DecryptError,
TLSError::PeerIncompatibleError("no tls1.2".to_string()),
TLSError::PeerMisbehavedError("inconsistent something".to_string()),
TLSError::AlertReceived(AlertDescription::ExportRestriction),
TLSError::WebPKIError(webpki::Error::ExtensionValueInvalid),
TLSError::General("undocumented error".to_string())
];
for err in all {
println!("{:?}:", err);
println!(" desc '{}'", err.description());
println!(" fmt '{}'", err);
}
}
}