Add encrypted managed UDP relay and native voice conformance

This commit is contained in:
2026-09-15 22:53:54 +02:00
parent 4067bab7c2
commit 05eacb3092
19 changed files with 1068 additions and 46 deletions
+15 -7
View File
@@ -82,7 +82,8 @@ mandatory from the first build. This was chosen over DTLS after weighing two fin
`0x01` for server→client. Each export yields a 32-byte directional media key.
No second handshake, no certificates on the UDP path — the UDP channel inherits the
authenticated, MITM-resistant TLS session's trust.
2. Each UDP voice frame is sealed with **ChaCha20-Poly1305** (libsodium, ISC license).
2. Each UDP voice frame is sealed with **ChaCha20-Poly1305** (libsodium in C++;
platform cryptography with a BouncyCastle fallback in .NET).
3. The full 20-byte header is AEAD **associated data**. The server authenticates/decrypts
inbound media and reseals for each recipient, replacing the sequence with that
recipient's next send counter. It forwards the encoded Opus bytes without decoding audio.
@@ -115,14 +116,21 @@ the design depends on that.
UDP packets are not individually authenticated to a *user* beyond the transport session.
Binding works as:
1. `AuthResult.udp_token` (issued over TLS) is a short-lived, single-use, random token tied
to `session_id`.
2. Client's first UDP message is `UdpBinding{udp_token}`, sent as the first AEAD media frame
using the keys exported from the TLS session.
3. Server validates the token, binds the **5-tuple → session_id**, and discards the token.
1. `AuthResult.udp_token` (issued over TLS) is a random 16-byte token tied to the
authenticated session. The client confirms it with `UdpBinding` over TLS.
2. Protocol v2 bootstraps UDP with a **plaintext** `UDP_BINDING` packet: the 20-byte
binary header followed by the token. This is not a protobuf or an AEAD voice frame.
3. Server validates the token and binds the **5-tuple → session_id**. The managed server
accepts the first endpoint only; further bootstrap packets cannot replace it.
Endpoint changes require a new authenticated session. The token remains available
for TLS confirmation but cannot establish a second binding. Session removal retires
its endpoint, token and directional keys. The C++ oracle currently permits rebinding
with the same token; this differs in policy, not in the packet format.
4. Thereafter, frames are accepted only on that bound tuple; ssrcs are checked against the
streams the session announced. Source-address spoofing can't hijack a session because the
attacker lacks the media key and the token.
attacker lacks the media key. The bootstrap token is visible on UDP, so it is not
a substitute for AEAD authentication and SSRC ownership checks. Header-only keepalives
are echoed only for bound endpoints; they provide liveness, not authenticated content.
## 4. Authentication & accounts (settled: guests + local accounts)