}
impl OssuaryConnection {
+ /// Encrypts data into a packet suitable for sending over the network
+ ///
+ /// The caller provides unencrypted plaintext data, in any format, in the
+ /// `in_buf` buffer. `send_data()` encrypts it and writes it in the proper
+ /// packet format into `out_buf`.
+ ///
+ /// This is the core function for data transmission via ossuary. All data
+ /// to be sent over an Ossuary connection should pass through this function.
+ ///
+ /// Note that Ossuary does not perform network operations itself. It is the
+ /// caller's responsibility to put the written data on the wire. However,
+ /// you may pass a 'buf' that does this automatically, such as a TcpStream.
+ ///
+ /// Returns the number of bytes written to `out_buf`, or an error.
+ ///
+ /// You must handle [`OssuaryError::WouldBlock`], which is a recoverable
+ /// error, but indicates that some bytes were written to the buffer. If any
+ /// bytes are written to `out_buf`, it can be assumed that all of `in_buf`
+ /// was consumed. In the event of a `WouldBlock` error, you can either
+ /// continue calling `send_data()` with the next data to be sent, or you can
+ /// use [`OssuaryConnection::flush()`] to explicitly finish writing the
+ /// packet.
pub fn send_data<T,U>(&mut self,
in_buf: &[u8],
mut out_buf: T) -> Result<usize, OssuaryError>
Ok(written)
}
+ /// Decrypts data from a packet received from a remote host
+ ///
+ /// The caller provides encrypted data from a remote host in the `in_buf`
+ /// buffer. `recv_data()` decrypts it and writes the plaintext result into
+ /// `out_buf`.
+ ///
+ /// This is the core function for data transmission via ossuary. All data
+ /// received over an Ossuary connection should pass through this function.
+ ///
+ /// Returns the number of bytes written to `out_buf`, or an error.
+ ///
+ /// You must handle [`OssuaryError::WouldBlock`], which is a recoverable
+ /// error, but indicates that some bytes were read from `in_buf`. This
+ /// indicates that an incomplete packet was received.
pub fn recv_data<T,U,R,V>(&mut self,
in_buf: T,
mut out_buf: R) -> Result<(usize, usize), OssuaryError>
Ok((bytes_read, bytes_written))
}
+ /// Write any cached encrypted data waiting to be sent
+ ///
+ /// If a previous call to [`OssuaryConnection::send_data`] was unable to
+ /// write out all of its data, the remaining data is cached internally. It
+ /// can be explicitly flushed by calling this function until it returns 0.
+ ///
+ /// After each call, it is the caller's responsibility to put the written
+ /// data onto the network, unless `out_buf` is an object that handles that
+ /// implicitly, such as a TcpStream.
pub fn flush<R,V>(&mut self,
mut out_buf: R) -> Result<usize, OssuaryError>
where R: std::ops::DerefMut<Target = V>,
//
#[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.
///
/// 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.
}
impl OssuaryConnection {
+ /// Write the next handshake packet into the given buffer
+ ///
+ /// If a handshake packet is ready to be sent, this function writes the
+ /// encrypted packet into the provided buffer.
+ ///
+ /// This is a critical part of the handshaking stage, when a connection to
+ /// a remote host is securely established. Each side of the connection must
+ /// call send_handshake() continuously, and any data that is written to the
+ /// data buffer must be sent to the remote host. This should be done until
+ /// [`OssuaryConnection::handshake_done()`] returns true.
+ ///
+ /// Note that Ossuary does not perform network operations itself. It is the
+ /// caller's responsibility to put the written data on the wire. However,
+ /// you may pass a 'buf' that does this automatically, such as a TcpStream.
+ ///
+ /// Returns the number of bytes written into `buf`, or an error. You must
+ /// handle [`OssuaryError::WouldBlock`], which is a recoverable error, but
+ /// indicates that some bytes were written to the buffer.
pub fn send_handshake<T,U>(&mut self, mut buf: T) -> Result<usize, OssuaryError>
where T: std::ops::DerefMut<Target = U>,
U: std::io::Write {
}
Ok(written)
}
+
+ /// Read the next handshake packet from the given buffer
+ ///
+ /// If a handshake packet has been received, this function reads and parses
+ /// the encrypted packet from the provided buffer and updates its internal
+ /// connection state.
+ ///
+ /// This is a critical part of the handshaking stage, when a connection to
+ /// a remote host is securely established. Each side of the connection must
+ /// call recv_handshake() whenever data is received from the network until
+ /// [`OssuaryConnection::handshake_done()`] returns true.
+ ///
+ /// Returns the number of bytes read from `buf`, or an error. It is the
+ /// caller's responsibility to ensure that the consumed bytes are removed
+ /// from the data buffer before it is used again. You must handle
+ /// [`OssuaryError::WouldBlock`], which is a recoverable error, but
+ /// indicates that some bytes were also read from the buffer.
pub fn recv_handshake<T,U>(&mut self, buf: T) -> Result<usize, OssuaryError>
where T: std::ops::DerefMut<Target = U>,
U: std::io::Read {
#![doc(html_no_source)]
//! # Ossuary
//!
-//! Ossuary is a library for establishing an encrypted and authenticated
-//! communication channel between a client and a server.
+//! Ossuary is a Rust library for establishing an encrypted and
+//! authenticated communication channel between a client and a server.
//!
//! It establishes a 1-to-1 client/server communication channel that requires
//! reliable, in-order packet delivery, such as provided by TCP sockets.
//! Authentication and verification of remote hosts is optional, and requires
//! an out-of-band exchange of host public keys, or a Trust-On-First-Use policy.
//!
+//! Ossuary includes a C FFI API, and can be built as a native dynamic or static
+//! library for linking into C or C++ binaries.
+//!
//! ## Protocol Overview:
//!
//! The Ossuary protocol consists of two distinct stages: a handshaking stage
/// in exchange they can read and write from/to streams set in non-blocking mode
/// without blocking single-threaded applications.
///
+/// Establishing a connection involves calling
+/// [`OssuaryConnection::send_handshake`] and
+/// [`OssuaryConnection::recv_handshake`] in a loop until
+/// [`OssuaryConnection::handshake_done`] returns true.
+///
+/// Once established, data to encrypt and send is passed to
+/// [`OssuaryConnection::send_data`] and received data to decrypt is
+/// passed to [`OssuaryConnection::recv_data`].
+///
+/// Your program should be structured so that any failures during
+/// transmission cause it to fall back to the handshake loop to
+/// attempt a reconnection.
+///
pub struct OssuaryConnection {
state: ConnectionState,
conn_type: ConnectionType,