sealed_channel/error.rs
1//! Error type for the sealed channel.
2//!
3//! The variants are intentionally *detailed* so that internal logic and tests
4//! can distinguish failure modes precisely. However, the **consumer** of this
5//! crate (not this crate itself) is responsible for collapsing any error into a
6//! single, generic reason before it is exposed on a wire or to a remote peer.
7//! Leaking the precise failure reason (e.g. distinguishing an out-of-order
8//! frame from an authentication failure) to an attacker can create oracles, so
9//! callers should map every [`Error`] to one opaque "channel error" externally.
10
11use core::fmt;
12
13/// Errors produced by the sealed channel.
14///
15/// This crate never panics on attacker-controlled input; every fallible
16/// operation returns one of these variants instead.
17///
18/// Note: this type intentionally does **not** implement `std::error::Error`
19/// because the crate is `#![no_std]`.
20#[non_exhaustive]
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum Error {
23 /// The supplied Diffie-Hellman shared secret is all-zero.
24 ///
25 /// X25519 produces an all-zero output for low-order points (RFC 7748),
26 /// which would make the resulting keys predictable; such a secret is
27 /// rejected with a constant-time check.
28 WeakSharedSecret,
29 /// The HKDF key-derivation step failed (e.g. an `expand` length error).
30 KeyDerivation,
31 /// AEAD decryption (authentication) failed: the frame was tampered with,
32 /// the keys do not match, or the nonce/AAD did not correspond.
33 Decrypt,
34 /// A frame arrived with a sequence number other than the next expected
35 /// one (replay or reordering).
36 OutOfOrder,
37 /// The 64-bit sequence counter is exhausted. The channel fails closed
38 /// rather than wrapping or reusing a nonce.
39 SequenceExhausted,
40 /// A frame was too short, or did not begin with the expected magic byte.
41 MalformedFrame,
42}
43
44impl fmt::Display for Error {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 let msg = match self {
47 Error::WeakSharedSecret => "weak (all-zero) Diffie-Hellman shared secret",
48 Error::KeyDerivation => "key derivation failed",
49 Error::Decrypt => "AEAD authentication/decryption failed",
50 Error::OutOfOrder => "frame sequence number out of order",
51 Error::SequenceExhausted => "sequence counter exhausted",
52 Error::MalformedFrame => "malformed frame",
53 };
54 f.write_str(msg)
55 }
56}