use crate::asn1::Frame;
use crate::policy::TransitStatus;
#[cfg(feature = "derive")]
use crate::Errorizable;
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
pub type Result<T> = core::result::Result<T, TransportError>;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TransportFailure {
EncodingFailed,
EncryptionFailed,
SizeExceeded,
EncryptorUnavailable,
NonceGenerationFailed,
Busy,
Forbidden,
Unauthorized,
Timeout,
PolicyRejection,
}
#[cfg_attr(feature = "derive", derive(Errorizable))]
#[derive(Debug)]
pub enum TransportError {
#[cfg_attr(feature = "derive", error("Connection closed gracefully"))]
ConnectionClosed,
#[cfg_attr(feature = "derive", error("Connection failed"))]
ConnectionFailed,
#[cfg_attr(feature = "derive", error("Send failed"))]
SendFailed,
#[cfg_attr(feature = "derive", error("Encryption required but not provided"))]
MissingEncryption,
#[cfg_attr(
feature = "derive",
error("Handshake protocol not supported by this transport: {0:?}")
)]
UnsupportedHandshakeProtocol(crate::transport::handshake::HandshakeProtocolKind),
#[cfg_attr(
feature = "derive",
error("Server certificate chain required but not provisioned")
)]
MissingServerCertificateChain,
#[cfg_attr(feature = "derive", error("Invalid message"))]
InvalidMessage,
#[cfg_attr(feature = "derive", error("Invalid reply"))]
InvalidReply,
#[cfg_attr(feature = "derive", error("Missing request"))]
MissingRequest,
#[cfg_attr(feature = "derive", error("Max retries exceeded"))]
MaxRetriesExceeded,
#[cfg_attr(feature = "derive", error("Invalid address"))]
InvalidAddress,
#[cfg_attr(feature = "derive", error("Invalid state"))]
InvalidState,
#[cfg(feature = "x509")]
#[cfg_attr(feature = "derive", error("Invalid certificate: {0}"))]
#[cfg_attr(feature = "derive", from)]
InvalidCertificate(crate::crypto::x509::error::CertificateValidationError),
#[cfg_attr(feature = "derive", error("Message not sent: {1:?} - {0:?}"))]
MessageNotSent(Box<Frame>, TransportFailure),
#[cfg_attr(feature = "derive", error("Operation failed: {0:?}"))]
OperationFailed(TransportFailure),
#[cfg(feature = "x509")]
#[cfg_attr(feature = "derive", error("Handshake error: {0}"))]
#[cfg_attr(feature = "derive", from)]
HandshakeError(crate::transport::handshake::HandshakeError),
#[cfg_attr(feature = "derive", error("DER error: {0}"))]
#[cfg_attr(feature = "derive", from)]
DerError(der::Error),
#[cfg(feature = "std")]
#[cfg_attr(feature = "derive", error("I/O error: {0}"))]
#[cfg_attr(feature = "derive", from)]
IoError(std::io::Error),
}
crate::impl_error_display!(TransportError {
ConnectionClosed => "Connection closed gracefully",
ConnectionFailed => "Connection failed",
SendFailed => "Send failed",
MissingEncryption => "Encryption required but not provided",
UnsupportedHandshakeProtocol(kind) => "Handshake protocol not supported by this transport: {kind:?}",
MissingServerCertificateChain => "Server certificate chain required but not provisioned",
InvalidMessage => "Invalid message",
InvalidReply => "Invalid reply",
MissingRequest => "Missing request",
MaxRetriesExceeded => "Max retries exceeded",
InvalidAddress => "Invalid address",
InvalidState => "Invalid state",
MessageNotSent(frame, failure) => "Message not sent: {failure:?} - {frame:?}",
OperationFailed(failure) => "Operation failed: {failure:?}",
DerError(err) => "DER error: {err}",
#[cfg(feature = "x509")]
InvalidCertificate(err) => "Invalid certificate: {err}",
#[cfg(feature = "x509")]
HandshakeError(err) => "Handshake error: {err}",
#[cfg(feature = "std")]
IoError(err) => "I/O error: {err}",
});
impl From<crate::error::TightBeamError> for TransportError {
fn from(err: crate::error::TightBeamError) -> Self {
use crate::error::TightBeamError;
match err {
TightBeamError::TransportError(t) => t,
TightBeamError::SerializationError(e) => TransportError::DerError(e),
#[cfg(feature = "x509")]
TightBeamError::HandshakeError(h) => TransportError::HandshakeError(h),
#[cfg(feature = "x509")]
TightBeamError::CertificateValidationError(e) => TransportError::InvalidCertificate(e),
#[cfg(feature = "std")]
TightBeamError::IoError(e) => TransportError::IoError(e),
_ => TransportError::InvalidMessage,
}
}
}
impl From<TransitStatus> for TransportError {
fn from(status: TransitStatus) -> Self {
match status {
TransitStatus::Request => TransportError::InvalidMessage,
TransitStatus::Accepted => TransportError::InvalidMessage,
TransitStatus::Busy => TransportError::OperationFailed(TransportFailure::Busy),
TransitStatus::Unauthorized => TransportError::OperationFailed(TransportFailure::Unauthorized),
TransitStatus::Forbidden => TransportError::OperationFailed(TransportFailure::Forbidden),
TransitStatus::Timeout => TransportError::OperationFailed(TransportFailure::Timeout),
}
}
}
#[cfg(all(feature = "std", not(feature = "derive")))]
crate::impl_from!(std::io::Error => TransportError::IoError);
#[cfg(not(feature = "derive"))]
crate::impl_from!(der::Error => TransportError::DerError);
#[cfg(all(feature = "x509", not(feature = "derive")))]
crate::impl_from!(crate::transport::handshake::HandshakeError => TransportError::HandshakeError);
#[cfg(all(feature = "x509", not(feature = "derive")))]
crate::impl_from!(crate::crypto::x509::error::CertificateValidationError => TransportError::InvalidCertificate);
crate::impl_from!(
spki::Error => TransportError::DerError extract spki::Error::Asn1(der_err) =>
der_err else der::Error::from(der::ErrorKind::Failed)
);
#[cfg(feature = "x509")]
crate::impl_from!(
x509_cert::builder::Error => TransportError::DerError extract x509_cert::builder::Error::Asn1(der_err) =>
der_err else der::Error::from(der::ErrorKind::Failed)
);
#[cfg(all(feature = "std", feature = "tcp"))]
impl From<std::net::AddrParseError> for TransportError {
fn from(err: std::net::AddrParseError) -> Self {
TransportError::IoError(std::io::Error::new(std::io::ErrorKind::InvalidInput, err))
}
}
#[cfg(feature = "tokio")]
impl From<tokio::task::JoinError> for TransportError {
fn from(err: tokio::task::JoinError) -> Self {
TransportError::IoError(std::io::Error::other(err))
}
}
#[cfg(feature = "tokio")]
impl From<tokio::time::error::Elapsed> for TransportError {
fn from(_: tokio::time::error::Elapsed) -> Self {
TransportError::OperationFailed(TransportFailure::Timeout)
}
}
#[cfg(all(feature = "x509", feature = "secp256k1"))]
impl From<k256::ecdsa::Error> for TransportError {
fn from(err: k256::ecdsa::Error) -> Self {
TransportError::HandshakeError(crate::transport::handshake::HandshakeError::from(err))
}
}
impl TransportError {
pub fn from_failure(frame: Frame, failure: TransportFailure) -> Self {
TransportError::MessageNotSent(Box::new(frame), failure)
}
pub fn take_frame(self) -> Option<crate::asn1::Frame> {
match self {
TransportError::MessageNotSent(frame, _) => Some(*frame),
_ => None,
}
}
pub fn frame(&self) -> Option<&crate::asn1::Frame> {
match self {
TransportError::MessageNotSent(frame, _) => Some(frame),
_ => None,
}
}
pub fn failure_reason(&self) -> Option<&TransportFailure> {
match self {
TransportError::MessageNotSent(_, reason) => Some(reason),
_ => None,
}
}
pub fn is_connection_error(&self) -> bool {
matches!(
self,
TransportError::ConnectionClosed
| TransportError::ConnectionFailed
| TransportError::OperationFailed(TransportFailure::Timeout)
) || {
#[cfg(feature = "std")]
{
matches!(self, TransportError::IoError(_))
}
#[cfg(not(feature = "std"))]
{
false
}
}
}
}
impl From<TransportFailure> for TransportError {
fn from(failure: TransportFailure) -> Self {
match failure {
TransportFailure::EncodingFailed => TransportError::InvalidMessage,
TransportFailure::SizeExceeded => TransportError::InvalidMessage,
TransportFailure::PolicyRejection => TransportError::InvalidReply,
TransportFailure::NonceGenerationFailed => TransportError::SendFailed,
other => TransportError::OperationFailed(other),
}
}
}
impl TransportFailure {
pub fn with_frame(self, frame: Frame) -> TransportError {
TransportError::from_failure(frame, self)
}
pub fn with_optional_frame(self, frame: Option<Frame>) -> TransportError {
if let Some(frame) = frame {
self.with_frame(frame)
} else {
self.into()
}
}
}