From 95c06a4dae955ccfbd3a85f957ee993fe1828e68 Mon Sep 17 00:00:00 2001 From: ghost Date: Sun, 28 Dec 2025 22:24:43 +0100 Subject: [PATCH] Chg: Test long-term and short-term key. --- src/auth.rs | 13 +++++++++++-- src/stun.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index efb4bb4..86256d7 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -3,7 +3,7 @@ use crate::config::AuthOptions; use crate::constants::{ATTR_NONCE, ATTR_REALM, ATTR_USERNAME}; use crate::models::stun::StunMessage; -use crate::stun::{find_message_integrity, validate_message_integrity}; +use crate::stun::{find_message_integrity, validate_message_integrity, validate_message_integrity_len_preserved}; use crate::traits::CredentialStore; use async_trait::async_trait; use base64::Engine; @@ -187,7 +187,9 @@ impl AuthManager { // Workaround: also accept short-term style (raw password as key) for test clients like turnutils_uclient. let short_key = password.as_bytes(); - if validate_message_integrity(msg, short_key) { + if validate_message_integrity(msg, short_key) + || validate_message_integrity_len_preserved(msg, short_key) + { warn!("auth accept via short-term key username={} realm={} peer={} (workaround)", username, realm, peer); return AuthStatus::Granted { username, @@ -195,6 +197,13 @@ impl AuthManager { }; } + // Additional interop fallback: some clients miscompute length when adding FINGERPRINT; + // try validation without adjusting the header length. + if validate_message_integrity_len_preserved(msg, &key) { + warn!("auth accept via len-preserved MI username={} realm={} peer={} (interop fallback)", username, realm, peer); + return AuthStatus::Granted { username, key }; + } + let key_hex = hex::encode(&key); warn!("auth reject: bad credentials username={} realm={} peer={} a1_md5={} (debug)", username, realm, peer, key_hex); AuthStatus::Reject { diff --git a/src/stun.rs b/src/stun.rs index 193561b..2406196 100644 --- a/src/stun.rs +++ b/src/stun.rs @@ -386,6 +386,32 @@ pub fn validate_message_integrity(msg: &StunMessage, key: &[u8]) -> bool { false } +/// Fallback validator: compute MESSAGE-INTEGRITY without adjusting the STUN header length. +/// Some clients incorrectly leave the header length unchanged when appending FINGERPRINT; +/// this matches that behaviour for interop. +pub fn validate_message_integrity_len_preserved(msg: &StunMessage, key: &[u8]) -> bool { + if let Some(mi) = find_message_integrity(msg) { + if mi.value.len() != HMAC_SHA1_LEN { + return false; + } + + let mi_end = mi.offset + 4 + HMAC_SHA1_LEN; + if mi_end > msg.raw.len() { + return false; + } + + let mut signed = msg.raw[..mi_end].to_vec(); + let value_start = mi.offset + 4; + for b in &mut signed[value_start..value_start + HMAC_SHA1_LEN] { + *b = 0; + } + + let computed = crate::stun::compute_message_integrity(key, &signed); + return &computed[..HMAC_SHA1_LEN] == mi.value.as_slice(); + } + false +} + fn append_message_integrity(buf: &mut bytes::BytesMut, key: &[u8]) { // Append attribute header and placeholder; set length to end-of-MI, then compute // HMAC over the message slice up to end-of-MI (with the MI placeholder still zero).