src/lib.rs
//! # Ossuary
//!
//! 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
//! and an established channel stage.
//!
//! ## Handshake
//!
//! All connections begin by handshaking. A few packets are exchanged back and
//! forth to establish an encrypted channel with a negotiated session key, and
//! to optionally authenticate the identity of the hosts. Handshake packets are
//! generated by the Ossuary library itself; the application asks Ossuary for
//! the next packet to send, and then is responsible for putting it on the wire.
//!
//! ## Established Channel
//!
//! Once the handshake completes successfully, Ossuary drops into the
//! established channel stage. In this stage, Ossuary is completely passive,
//! where the application gives it data to encrypt for transmission or decrypt
//! for reception. Ossuary does not generate any unrequested packets in this
//! stage.
//!
//! In the case of errors, Ossuary always terminates the encrypted channel and
//! drops back into the handshake stage. If it believes the channel might still
//! be viable, the handshake stage will generate a packet to attempt to reset
//! the remote host back into the handshake as well, and they will both attempt
//! to recover the channel.
//!
//! ## API Overview:
//!
//! Ossuary fits into an application as a 'filter' on network traffic, and does
//! not implement any network communication itself. Similarly, it does not have
//! any persistent storage, leaving the storage of keys to the caller.
//!
//! The application must always check to see if it should drop back into the
//! handshake, in case the connection failed. The main loop would typically be
//! split between two cases: handshaking, or established channel.
//!
//! In pseudocode, typical use of the API looks like this:
//!
//! ```ignore
//! fn main() {
//! let socket = TCPSocket::get_socket_from_somewhere();
//! let secret_key = FileSystem::get_securely_stored_file("secret.key");
//! let ossuary = OssuaryConnection::new(ConnectionType::Whatever, Some(secret_key));
//! let net_read_buf = [0u8; 1024]; // encrypted!
//! let net_write_buf = [0u8; 1024]; // encrypted!
//! let internal_buf = [0u8; 1024]; // plaintext!
//!
//! loop {
//! // Always read encrypted data off the wire and append to our read buf
//! socket.read_and_append(&mut net_read_buf);
//!
//! // Two paths depending on if we are handshaking
//! match ossuary.handshake_done() {
//! false => {
//! // Parse received handshake packets.
//! ossuary.recv_handshake(&net_read_buf);
//!
//! // Possibly write handshake packets.
//! ossuary.send_handshake(&mut net_write_buf);
//! },
//!
//! true => {
//! // Decrypt data into internal buffer
//! ossuary.recv_data(&net_read_buf, &mut internal_buf);
//!
//! // Do some application-specific thing with the data
//! react_and_respond(&mut internal_buf);
//!
//! // Encrypt application's response
//! ossuary.send_data(&internal_buf, &mut net_write_buf);
//! },
//! }
//!
//! // Always write all encrypted data onto the wire and clear the write buf
//! socket.write_and_clear(&mut net_write_buf);
//! }
//! }
//! ```
//!
//! A real implementation would also need to carefully handle removing consumed
//! bytes from the read buffer, and handling errors at every step.
//!
//! Since Ossuary leaves the actual wire transmission to the caller, it can be
//! used over any physical channel, or with any transmission protocol, so long
//! as data is delivered (to Ossuary) reliably and in-order. It is just as
//! viable for UNIX Domain Sockets, D-Bus, named pipes, and other IPC mechanisms
//! as for TCP, if you somehow have a threat model that distrusts those.
//!
//! ## Ciphers:
//!
//! * Ephemeral session keys: Curve25519 ECDH.
//! * Session encryption: ChaCha20 symmetrical cipher.
//! * Message authentication: Poly1305 MAC.
//! * Host authentication: Ed25519 signature scheme.
//!
//! ## The handshake protocol:
//!
//! A 3-packet (1.5 roundtrip) handshake is always performed.
//!
//! The necessary fields to perform an ECDH key exchange and establish a
//! shared session key are sent in the clear, while fields for host verification
//! are encrypted with the established session key.
//!
//! In the following diagram, fields in [single brackets] are sent in the clear,
//! and those in [[double brackets]] are encrypted with the shared session key:
//!
//! ```text
//! <client> --> [ session x25519 public key,
//! session nonce,
//! client random challenge ] --> <server>
//! <client> <-- [ session x25519 public key,
//! session nonce],
//! [[ auth ed25519 public key,
//! server random challenge,
//! signature(pubkey, nonce, challenge), ]] <-- <server>
//! <client> --> [[ auth ed25519 public key,
//! signature(pubkey, nonce, challenge), ]] --> <server>
//! ```
//!
//! Host authentication (verifying the identity of the remote server or client)
//! is optional. In non-authenticated flows, "auth public key", "challenge",
//! and "signature" fields are set to all 0s, but are still transmitted.
//!
//! ### Fields
//!
//! * **session public key**: Public part of randomly generated public/private
//! key pair for this session, used to generate an ephemeral session key.
//! * **challenge**: Randomly generated string for remote party to sign to prove
//! its identity in authenticated connections.
//! * **auth public key**: Public part of long-lived public/private key pair
//! used for host authentication.
//! * **signature**: Signature, with long-lived private authentication key, of
//! local party's session public key and nonce (the ECDH parameters) and
//! remote party's random challenge, to prove host identity and prevent
//! man-in-the-middle attacks.
//!
//! ## Security Protections
//!
//! ### Passive Snooping
//!
//! Per-packet encryption with ChaCha20 prevents passive monitoring of the
//! contents of the communication channel.
//!
//! ### Malleability
//!
//! Poly1305 MAC prevents active manipulation of packets in-flight, ensuring
//! that any manipulation will cause the channel to terminate.
//!
//! ### Replay Attacks
//!
//! Poly1305 MAC combined with a nonce scheme prevents replay attacks, and
//! prevents manipulation of message order.
//!
//! ### Forward Secrecy
//!
//! Per-session encryption with ephemeral x25519 keys ensures that the
//! compromise of one session does not necessarily result in the compromise of
//! any previous or future session.
//!
//! ### Man-in-the-Middle
//!
//! Host authentication with Ed25519 signature verification of ECDH parameters
//! prevents man-in-the-middle attacks. Host authentication is optional, and
//! requires out-of-band exchange of host public keys or a Trust On First Use
//! policy, so MITM attacks may be possible if care is not taken.
//!
//! ## Security Limitations
//!
//! ### Code Quality
//!
//! This software is not code reviewed, and no security analysis has been
//! performed.
//!
//! ### Keys In RAM
//!
//! No efforts are taken to secure key data in RAM. Attacks from privileged
//! local processes are possible.
//!
//! ### Keys On Disk
//!
//! No mechanisms are provided for storing keys on disk. Secure key storage
//! is left as a task for the caller.
//!
//! ### Side-Channel
//!
//! No efforts are taken to protect against side channel attacks such as timing
//! or cache analysis.
//!
//! ### Software Dependencies
//!
//! This software depends on third-party software libraries for all core
//! cryptographic algorithms, which have not been code reviewed and are subject
//! to change.
//!
//! ### Trust-On-First-Use (TOFU)
//!
//! Host authentication supports a trust-on-first-use policy, which opens the
//! possibility of man-in-the-middle attacks if the first connection is
//! compromised.
//!
//! # License
//!
//! 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.
//!
//
// TODO
// - rustdoc everything
//
pub use OssuaryError;
use ;
use ;
use ;
use OsRng;
const PROTOCOL_VERSION: u8 = 1u8;
// Maximum time to wait (in seconds) for a handshake response
const MAX_HANDSHAKE_WAIT_TIME: u64 = 3u64;
// Maximum number of times a connection can reset before a permanent failure.
const MAX_RESET_COUNT: usize = 5;
// Size of the random data to be signed by client
const CHALLENGE_LEN: usize = 32;
const SIGNATURE_LEN: usize = 64;
const KEY_LEN: usize = 32;
const NONCE_LEN: usize = 12;
const TAG_LEN: usize = 16; // chacha20 tag
// Internal buffer for copy of network data
const PACKET_BUF_SIZE: usize = 16384
+
+
+ TAG_LEN;
/// Internal struct for holding a complete network packet
/// The packet types used by the Ossuary protocol.
pub
/// Header prepended to the front of all encrypted data packets.
/// Header prepended to the front of all packets, regardless of encryption.
/// Internal state of OssuaryConnection state machine.
/// Enum specifying the client or server role of a [`OssuaryConnection`]
/// Context for interacting with an encrypted communication channel
///
/// All interaction with ossuary's encrypted channels is performed via a
/// OssuaryConnection instance. It holds all of the state required to maintain
/// one side of an encrypted connection.
///
/// A context is created with [`OssuaryConnection::new`], passing it a
/// [`ConnectionType`] identifying whether it is to act as a client or server.
/// Server contexts can optionally require authentication, verified by providing
/// a list of public keys of permitted clients with
/// [`OssuaryConnection::add_authorized_keys`]. Clients, on the other hand,
/// authenticate by setting their secret key with
/// [`OssuaryConnection::set_secret_key`].
///
/// A server must create one OssuaryConnection per connected client. Multiple
/// connections cannot be multiplexed in one context.
///
/// A OssuaryConnection keeps temporary buffers for both received and soon-to-be
/// transmitted data. This means they are not particularly small objects, but
/// 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.
///
/// Generate secret/public Ed25519 keypair for host authentication
/// Cast the data bytes in a NetworkPacket into a struct
/// Cast the data bytes in a NetworkPacket into a struct, and also return the
/// remaining unused bytes if the data is larger than the struct.