foctet_core/lib.rs
1//! Foctet Core (Draft v0)
2//! - Fixed-width frame header encoding
3//! - Profile 0x01 crypto primitives
4//! - Native handshake key schedule helpers
5//! - Replay window enforcement
6//! - Runtime-agnostic streaming adapters
7//!
8//! `foctet-core` is the low-level protocol crate for applications that need to
9//! drive Foctet sessions directly. If you already have a split stream transport
10//! such as QUIC, WebTransport, WebSocket multiplexing, or another byte-stream
11//! abstraction, prefer `foctet-transport` for the recommended handshake and
12//! channel builders.
13//!
14//! # Main Modules
15//!
16//! - [`body`]: `application/foctet` one-shot encrypted body envelope
17//! - [`frame`]: wire frame structures, parser/encoder, framed transport types
18//! - [`crypto`]: key schedule and frame AEAD helpers
19//! - [`control`]: control message wire payloads
20//! - [`session`]: handshake/rekey state machine
21//! - [`payload`]: encrypted payload TLV schema
22//! - [`io`]: runtime adapters and blocking `SyncIo`
23//!
24//! # Typical Flow
25//!
26//! 1. Build/derive [`TrafficKeys`] via handshake/session.
27//! 2. Send/receive via [`frame::FoctetFramed`] or [`io::SyncIo`].
28//! 3. Use [`Session`] to process control frames and rotate keys.
29//! 4. Encode application bytes as TLV (`APPLICATION_DATA`) via [`payload`].
30//!
31//! # Authentication Guidance
32//!
33//! - For production use, prefer [`SessionAuthConfig`] with local identity keys,
34//! pinned [`PeerIdentity`] values, and
35//! `SessionAuthConfig::require_peer_authentication(true)`.
36//! - If Foctet runs inside an already-authenticated outer channel, you may use
37//! the native handshake without identity signatures, but the outer channel
38//! then carries the peer-authentication responsibility.
39//! - Sequence numbers and rekey identifiers fail closed on exhaustion; callers
40//! should treat those errors as terminal and establish a fresh session.
41//!
42//! # Typical Native Handshake
43//!
44//! ```rust,ignore
45//! use foctet_core::{
46//! IdentityKeyPair, PeerIdentity, RekeyThresholds, Session, SessionAuthConfig,
47//! };
48//!
49//! let auth = SessionAuthConfig::new()
50//! .with_local_identity(IdentityKeyPair::generate())
51//! .with_peer_identity(PeerIdentity::new(peer_identity_public_key))
52//! .require_peer_authentication(true);
53//!
54//! let mut initiator = Session::new_initiator_with_auth(RekeyThresholds::default(), auth);
55//! let client_hello = initiator.start_handshake()?;
56//! # let _ = client_hello;
57//! # Ok::<(), foctet_core::CoreError>(())
58//! ```
59
60/// Handshake authentication helpers and identity-key types.
61pub mod auth;
62/// One-shot body-complete encrypted envelope (`application/foctet`) helpers.
63pub mod body;
64/// Control-plane message types used inside encrypted control frames.
65pub mod control;
66/// Cryptographic primitives and key-derivation helpers.
67pub mod crypto;
68/// Frame wire format, parser/encoder, and framed transport adapters.
69pub mod frame;
70/// Runtime adapters and blocking I/O wrappers.
71pub mod io;
72/// TLV payload encoding/decoding helpers for encrypted application bytes.
73pub mod payload;
74/// Replay-window tracking and duplicate-frame protection.
75pub mod replay;
76/// High-level blocking facade combining session/rekey and TLV application flow.
77pub mod secure_channel;
78/// Session handshake/rekey state and key lifecycle handling.
79pub mod session;
80
81pub use auth::{
82 HANDSHAKE_AUTH_ED25519, HANDSHAKE_AUTH_NONE, HandshakeAuth, IdentityKeyPair, PeerIdentity,
83 SessionAuthConfig,
84};
85pub use body::{
86 BODY_MAGIC, BODY_PROFILE_V0, BODY_VERSION_V0, BodyEnvelopeError, BodyEnvelopeLimits, open_body,
87 open_body_for_key_id, open_body_for_key_id_with_limits, open_body_with_limits, seal_body,
88 seal_body_with_limits,
89};
90pub use control::{ControlMessage, ControlMessageKind};
91pub use crypto::{
92 Direction, EphemeralKeyPair, TrafficKeys, decrypt_frame, decrypt_frame_with_key,
93 derive_rekey_traffic_keys, derive_traffic_keys, encrypt_frame, make_nonce, random_session_salt,
94};
95pub use frame::{
96 DRAFT_MAGIC, FRAME_HEADER_LEN, FoctetFramed, FoctetStream, Frame, FrameHeader,
97 PROFILE_X25519_HKDF_XCHACHA20POLY1305, WIRE_VERSION_V0,
98};
99pub use payload::{Tlv, decode_tlvs, encode_tlvs, tlv_type};
100pub use replay::{DEFAULT_REPLAY_WINDOW, ReplayProtector, ReplayWindow};
101pub use secure_channel::{AsyncSecureChannel, SecureChannel};
102pub use session::{HandshakeRole, RekeyThresholds, Session, SessionState};
103
104use thiserror::Error;
105
106/// Core protocol error type.
107#[derive(Debug, Error)]
108pub enum CoreError {
109 /// Frame header length is not `FRAME_HEADER_LEN`.
110 #[error("invalid frame header length: {0}")]
111 InvalidHeaderLength(usize),
112 /// Frame magic is invalid.
113 #[error("invalid frame magic")]
114 InvalidMagic,
115 /// Protocol version is unsupported.
116 #[error("unsupported version: {0}")]
117 UnsupportedVersion(u8),
118 /// Crypto profile is unsupported.
119 #[error("unsupported profile: {0}")]
120 UnsupportedProfile(u8),
121 /// Header flags contain unknown bits.
122 #[error("unknown or reserved flags are set: 0x{0:02x}")]
123 UnknownFlags(u8),
124 /// Header ciphertext length does not match payload length.
125 #[error("ciphertext length mismatch: expected {expected}, got {actual}")]
126 CiphertextLengthMismatch {
127 /// Declared ciphertext length from frame header.
128 expected: usize,
129 /// Actual ciphertext length found in frame body.
130 actual: usize,
131 },
132 /// AEAD operation failed.
133 #[error("aead operation failed")]
134 Aead,
135 /// HKDF expansion failed.
136 #[error("hkdf expand failed")]
137 Hkdf,
138 /// Symmetric key length is invalid.
139 #[error("invalid key length")]
140 InvalidKeyLength,
141 /// Received key ID does not match expected one.
142 #[error("unexpected key id: expected {expected}, got {actual}")]
143 UnexpectedKeyId {
144 /// Locally expected active key id.
145 expected: u8,
146 /// Key id found in the incoming frame.
147 actual: u8,
148 },
149 /// Control payload is malformed.
150 #[error("invalid control message")]
151 InvalidControlMessage,
152 /// Control payload is not valid for current protocol state.
153 #[error("unexpected control message for current state")]
154 UnexpectedControlMessage,
155 /// Session operation was called in an invalid state.
156 #[error("invalid session state")]
157 InvalidSessionState,
158 /// Session/shared secret is not available.
159 #[error("missing session secret")]
160 MissingSessionSecret,
161 /// TLV payload is malformed.
162 #[error("invalid tlv payload")]
163 InvalidTlv,
164 /// TLV payload exceeds configured limits.
165 #[error("tlv payload too large")]
166 TlvTooLarge,
167 /// Replay check detected a duplicate frame.
168 #[error("replay detected")]
169 Replay,
170 /// Frame sequence is outside replay window.
171 #[error("frame is outside replay window")]
172 ReplayWindowExceeded,
173 /// Frame exceeds configured size limits.
174 #[error("frame exceeds configured limit")]
175 FrameTooLarge,
176 /// Unexpected EOF while reading/writing frame bytes.
177 #[error("unexpected eof")]
178 UnexpectedEof,
179 /// Underlying I/O error.
180 #[error("io error: {0}")]
181 Io(#[from] std::io::Error),
182 /// X25519 produced a forbidden all-zero shared secret.
183 #[error("invalid shared secret")]
184 InvalidSharedSecret,
185 /// Outbound sequence space is exhausted and must not wrap.
186 #[error("sequence space exhausted")]
187 SequenceExhausted,
188 /// Rekey key identifier space is exhausted and must not wrap.
189 #[error("key id space exhausted")]
190 KeyIdExhausted,
191 /// Peer authentication was required but not present.
192 #[error("missing peer authentication")]
193 MissingPeerAuthentication,
194 /// Peer authentication failed validation.
195 #[error("invalid peer authentication")]
196 InvalidPeerAuthentication,
197 /// Peer identity did not match the pinned expectation.
198 #[error("peer identity mismatch")]
199 PeerIdentityMismatch,
200}