src/error.rs
//
// Copyright 2019 Trevor Bentley
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#[derive(Clone, PartialEq)]
/// Error produced by Ossuary or one of its dependencies
///
/// The most important errors that all programs must explicitly consider are:
/// - [`OssuaryError::UntrustedServer`]
/// - [`OssuaryError::WouldBlock`]
/// - [`OssuaryError::ConnectionReset`]
/// - [`OssuaryError::ConnectionFailed`]
/// - [`OssuaryError::ConnectionClosed`]
pub enum OssuaryError {
/// A problem with I/O read or writes.
///
/// An Io error is most likely raised when using an input or output buffer
/// that is more complex than a simple in-memory buffer, such as a
/// [`std::net::TcpStream`]
Io(String),
/// A buffer cannot complete a read/write without blocking.
///
/// Ossuary is inherently a non-blocking library, and returns this error any
/// time it is unable to read or write more data.
///
/// When using a buffer configured for non-blocking operation, such as a
/// [`std::net::TcpStream`], any non-blocking errors
/// ([`std::io::ErrorKind::WouldBlock`]) encounted by the buffer are raised
/// as this error.
///
/// The error has a paired parameter indicating whether any data WAS read
/// or written (depending on the function called). This can be non-zero
/// on operations that require multiple consecutive read/write operations
/// to the buffer if some but not all operations succeeded.
///
/// When using an input or output buffer in a manner that requires manually
/// sending or clearing data from the buffer, such as when passing the data
/// from Ossuary through an in-memory buffer prior to handing it to a TCP
/// connection, the amount of bytes indicated by the paired parameter should
/// be processed immediately.
WouldBlock(usize), // bytes consumed
/// Connection accepted by an unknown/untrusted server.
///
/// Returned when, during the handshake process, the server correctly
/// verifies itself, but its public key is not specified as an authorized
/// key. The caller may use this to implement a Trust-On-First-Use (TOFU)
/// policy.
///
/// This error contains the public key of the remote server.
///
/// After this is returned, the handshake process is paused until the caller
/// verifies that the key is to be trusted by calling [`add_authorized_keys`]
/// with the returned public key. This should only be done if the user has
/// opted for a TOFU policy, and this is the first time connecting to this
/// remote host.
///
/// It is the caller's responsibility to save a database of (host, key)
/// pairs when implementing TOFU.
///
/// [`add_authorized_keys`]: crate::OssuaryConnection::add_authorized_keys
UntrustedServer(Vec<u8>), // bytes consumed, public key
/// Error casting received bytes to a primitive type.
///
/// This error likely indicates a sync or corruption error in the data
/// stream, and will trigger a connection reset.
Unpack(String),
/// Error reading from random number generator
NoRandomSource,
/// An invalid sized encryption key was encountered.
///
/// This error is most likely caused by an attempt to register an invalid
/// secret or public key in [`add_authorized_keys`] or [`set_secret_key`].
/// Both should be 32 bytes.
///
/// [`add_authorized_keys`]: crate::OssuaryConnection::add_authorized_keys
/// [`set_secret_key`]: crate::OssuaryConnection::set_secret_key
KeySize(usize, usize), // (expected, actual)
/// An error occurred when parsing or using an encryption key.
///
/// This error indicates a problem when using an encryption key. This could
/// be because an expected key is missing, the format is incorrect, it was
/// corrupted in memory or in transit, or the wrong key was used.
///
/// This typically indicates an internal error, and will cause the
/// connection to reset.
InvalidKey,
/// Encrypted data failed to be decrypted
DecryptionFailed,
/// The channel received an unexpected or malformed packet
///
/// The associated string may describe the problem that went wrong. This
/// might be encountered if packets are duplicated, dropped, or corrupted.
/// It typically indicates an internal error, and the connection will reset.
InvalidPacket(String),
/// Error casting a received packet to an internal struct format.
///
/// This means a packet header was not found or corrupted, and will trigger
/// a connection reset.
InvalidStruct,
/// The signature received from a client failed to verify.
///
/// This either indicates a key mismatch (public and secret keys are not
/// a valid pair), corruption in the stream, or a problem during the
/// handshake. The connection will reset.
InvalidSignature,
/// Remote host running an incompatible protocol version
///
/// Parameters are (<remote version>, <local version>)
WrongProtocolVersion(u8, u8),
/// The connection has reset, and reconnection may be possible.
///
/// Ossuary does not attempt to recover from errors encountered on the data
/// stream. If anything has gone wrong, it resets the connection. When one
/// side resets, it always tells the other side to reset as well.
///
/// This error indicates that whatever went wrong may have been a temporal
/// fluke, such as momentary corruption or a sync error. Reconnection with
/// the same context may be possible. This must be handled by returning to
/// the handshake loop.
///
/// Includes the number of bytes consumed from the input buffer, if any,
/// at the time of the reset.
ConnectionReset(usize),
/// The connection has reset, and reconnection is not suggested.
///
/// This indicates that an error has occurred that Ossuary suspects is
/// permanent, and that a reconnect will not succeed. Errors include
/// failed authorization, such as a connection attempt fro a client whose
/// public key is not authorized.
///
/// When one side fails, it attempts to trigger a failure on the other side
/// as well.
ConnectionFailed,
/// The connection has been closed by request.
///
/// This indicates that the connection has been permanently closed by
/// the local side's request, and not because of an error. A call to
/// [`disconnect`] triggers this.
///
/// [`disconnect`]: crate::OssuaryConnection::disconnect
ConnectionClosed,
}
impl std::fmt::Debug for OssuaryError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
OssuaryError::Io(e) => write!(f, "OssuaryError::Io {}", e),
OssuaryError::WouldBlock(_) => write!(f, "OssuaryError::WouldBlock"),
OssuaryError::Unpack(_) => write!(f, "OssuaryError::Unpack"),
OssuaryError::NoRandomSource => write!(f, "OssuaryError::NoRandomSource"),
OssuaryError::KeySize(_,_) => write!(f, "OssuaryError::KeySize"),
OssuaryError::InvalidKey => write!(f, "OssuaryError::InvalidKey"),
OssuaryError::InvalidPacket(m) => write!(f, "OssuaryError::InvalidPacket: {}", m),
OssuaryError::InvalidStruct => write!(f, "OssuaryError::InvalidStruct"),
OssuaryError::InvalidSignature => write!(f, "OssuaryError::InvalidSignature"),
OssuaryError::ConnectionReset(_) => write!(f, "OssuaryError::ConnectionReset"),
OssuaryError::ConnectionFailed => write!(f, "OssuaryError::ConnectionFailed"),
OssuaryError::ConnectionClosed => write!(f, "OssuaryError::ConnectionClosed"),
OssuaryError::UntrustedServer(_) => write!(f, "OssuaryError::UntrustedServer"),
OssuaryError::DecryptionFailed => write!(f, "OssuaryError::DecryptionFailed"),
OssuaryError::WrongProtocolVersion(r,l) => write!(f, "OssuaryError:WrongProtocolVersion {} != {}", r, l),
}
}
}
impl From<std::io::Error> for OssuaryError {
fn from(error: std::io::Error) -> Self {
match error.kind() {
std::io::ErrorKind::WouldBlock => OssuaryError::WouldBlock(0),
_ => OssuaryError::Io(error.to_string()),
}
}
}
impl From<core::array::TryFromSliceError> for OssuaryError {
fn from(error: core::array::TryFromSliceError) -> Self {
OssuaryError::Unpack(error.to_string())
}
}
impl From<ed25519_dalek::SignatureError> for OssuaryError {
fn from(_error: ed25519_dalek::SignatureError) -> Self {
OssuaryError::InvalidSignature
}
}
impl From<chacha20_poly1305_aead::DecryptError> for OssuaryError {
fn from(_error: chacha20_poly1305_aead::DecryptError) -> Self {
OssuaryError::DecryptionFailed
}
}
impl From<rand::Error> for OssuaryError {
fn from(_error: rand::Error) -> Self {
OssuaryError::NoRandomSource
}
}