59b2358b87
Triaged the multi-agent review of the renegotiation + pairing + Sway + AV1/surround batch
(1 critical, 11 major/minor confirmed). Fixes:
CRITICAL — PIN pairing was offline-brute-forceable. The HMAC-of-PIN proof let an active
MITM who terminates the TOFU ceremony recover the 4-digit PIN by offline dictionary search
(all other inputs observable) and forge a correctly-bound proof. Replaced with **SPAKE2**
(balanced PAKE, `spake2` crate) + key-confirmation MACs, binding both cert fingerprints as
the SPAKE2 identities: an attacker gets exactly ONE online guess, no offline search, and
mismatched cert views (a real MITM) never reach a shared key. Also reworked the UX to an
"arming PIN" — one PIN per arming window shown at host startup (the SPAKE2 client needs the
PIN to build its first message, so it can't be minted per-connection). Validated live:
wrong PIN rejected in 0.1s, right PIN pairs + persists + the paired identity streams.
Pairing hardening: `--allow-pairing`/`--require-pairing` must arm pairing (default rejects
unsolicited ceremonies); per-host cooldown bounds online guessing; the client flushes its
CONNECTION_CLOSE so a refused ceremony can't wedge the sequential host for the full timeout;
atomic (temp+rename) paired-store writes.
Protocol: control/pairing messages use a distinct CTL_MAGIC (PKFc) — fully disjoint from
the positional Hello namespace (a future abi_version can't be misparsed as a control
message); all typed decodes are length-exact. ABI_VERSION → 2 (punktfunk_connect signature
gained the identity params; header regenerated).
Renegotiation: drain the reconfig channel to the NEWEST mode (one rebuild, not one per
stale step); validate refresh_hz; build the new pipeline BEFORE dropping the old so a
rebuild failure keeps the session on its current mode instead of killing it.
GameStream: packetDuration snaps to {5,10} (an in-between value isn't a legal Opus frame
size and would kill audio). Sway: chooser file moved to $XDG_RUNTIME_DIR (was a fixed
world-writable /tmp path — DoS / capture-misdirection by another local user).
Swift: fixed two compile breakers in the new pairing/identity APIs (Int32 status .rawValue,
UInt cap cast). New SPAKE2 + namespace-disjointness + pairing-roundtrip unit tests; the
in-process pairing test now also exercises the arming PIN + cooldown. 114 tests green,
clippy -D warnings clean (both feature sets), fmt, C-ABI harness.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
53 lines
2.2 KiB
Rust
53 lines
2.2 KiB
Rust
//! # punktfunk-core
|
|
//!
|
|
//! The shared protocol / transport / FEC core for the punktfunk low-latency streaming
|
|
//! stack. It is compiled exactly once and linked by every host and client — directly
|
|
//! as a Rust `lib`, or across the [C ABI](crate::abi) by Swift / Kotlin / C clients.
|
|
//!
|
|
//! Everything platform-specific (capture, encode, decode, present, input injection)
|
|
//! lives *outside* this crate. What lives *here*:
|
|
//!
|
|
//! - [`fec`] — erasure coding. GF(2⁸) for GameStream/Moonlight compatibility (P1) and
|
|
//! GF(2¹⁶) Leopard-RS (P2) which removes the ~1 Gbps per-frame shard-count ceiling.
|
|
//! - [`packet`] — `#[repr(C)]` zero-copy wire framing: splitting an access unit into
|
|
//! FEC blocks of MTU-sized shards and reassembling them on the far side.
|
|
//! - [`crypto`] — AES-128-GCM session sealing, matching GameStream in P1.
|
|
//! - [`session`] — the host (submit frame → FEC → packetize → seal → send) and client
|
|
//! (recv → open → reorder → FEC recover → reassemble) state machines.
|
|
//! - [`transport`] — pluggable packet I/O (in-process loopback for tests; UDP for real).
|
|
//! - [`abi`] — the `extern "C"` surface and `cbindgen`-generated `punktfunk_core.h`.
|
|
//!
|
|
//! ## Threading contract
|
|
//!
|
|
//! Nothing in the per-frame path touches an async runtime. `tokio`/`quinn` are gated
|
|
//! behind the off-by-default `quic` feature and used only for the control plane.
|
|
|
|
#![forbid(unsafe_op_in_unsafe_fn)]
|
|
|
|
pub mod abi;
|
|
#[cfg(feature = "quic")]
|
|
pub mod client;
|
|
pub mod config;
|
|
pub mod crypto;
|
|
pub mod error;
|
|
pub mod fec;
|
|
pub mod input;
|
|
pub mod packet;
|
|
#[cfg(feature = "quic")]
|
|
pub mod quic;
|
|
pub mod session;
|
|
pub mod stats;
|
|
pub mod transport;
|
|
|
|
pub use config::{Config, FecConfig, FecScheme, Mode, ProtocolPhase, Role};
|
|
pub use error::{PunktfunkError, PunktfunkStatus, Result};
|
|
pub use session::{Frame, Session};
|
|
pub use stats::Stats;
|
|
|
|
/// Bump on any breaking change to the [C ABI](crate::abi). Mirrors
|
|
/// `punktfunk_abi_version()` and is checked by clients before use.
|
|
///
|
|
/// v2: `punktfunk_connect` gained `client_cert_pem`/`client_key_pem` (pairing identities);
|
|
/// added `punktfunk_pair` / `punktfunk_generate_identity` / `punktfunk_connection_request_mode`.
|
|
pub const ABI_VERSION: u32 = 2;
|