Accept any one MI variants.
This commit is contained in:
parent
5486744bee
commit
abf9b87659
38
src/auth.rs
38
src/auth.rs
@ -5,6 +5,7 @@ use crate::constants::{ATTR_NONCE, ATTR_REALM, ATTR_USERNAME};
|
|||||||
use crate::models::stun::StunMessage;
|
use crate::models::stun::StunMessage;
|
||||||
use crate::stun::{
|
use crate::stun::{
|
||||||
compute_message_integrity_adjusted,
|
compute_message_integrity_adjusted,
|
||||||
|
compute_message_integrity_full,
|
||||||
compute_message_integrity_len_preserved as compute_mi_len_preserved,
|
compute_message_integrity_len_preserved as compute_mi_len_preserved,
|
||||||
find_message_integrity,
|
find_message_integrity,
|
||||||
validate_message_integrity,
|
validate_message_integrity,
|
||||||
@ -216,8 +217,37 @@ impl<S: CredentialStore + Clone> AuthManager<S> {
|
|||||||
let mi_long_len = compute_mi_len_preserved(msg, &key).map(hex::encode);
|
let mi_long_len = compute_mi_len_preserved(msg, &key).map(hex::encode);
|
||||||
let mi_short_adj = compute_message_integrity_adjusted(msg, short_key).map(hex::encode);
|
let mi_short_adj = compute_message_integrity_adjusted(msg, short_key).map(hex::encode);
|
||||||
let mi_short_len = compute_mi_len_preserved(msg, short_key).map(hex::encode);
|
let mi_short_len = compute_mi_len_preserved(msg, short_key).map(hex::encode);
|
||||||
|
let mi_long_full_adj = compute_message_integrity_full(msg, &key, true).map(hex::encode);
|
||||||
|
let mi_long_full_len = compute_message_integrity_full(msg, &key, false).map(hex::encode);
|
||||||
|
let mi_short_full_adj = compute_message_integrity_full(msg, short_key, true).map(hex::encode);
|
||||||
|
let mi_short_full_len = compute_message_integrity_full(msg, short_key, false).map(hex::encode);
|
||||||
|
|
||||||
|
// Accept if any variant matches received MI (still requires correct key).
|
||||||
|
if let Some(mi_attr_val) = find_message_integrity(msg) {
|
||||||
|
let mi_bytes = &mi_attr_val.value;
|
||||||
|
let variants: [(&str, Option<Vec<u8>>); 8] = [
|
||||||
|
("long_adj", compute_message_integrity_adjusted(msg, &key)),
|
||||||
|
("long_len", compute_mi_len_preserved(msg, &key)),
|
||||||
|
("short_adj", compute_message_integrity_adjusted(msg, short_key)),
|
||||||
|
("short_len", compute_mi_len_preserved(msg, short_key)),
|
||||||
|
("long_full_adj", compute_message_integrity_full(msg, &key, true)),
|
||||||
|
("long_full_len", compute_message_integrity_full(msg, &key, false)),
|
||||||
|
("short_full_adj", compute_message_integrity_full(msg, short_key, true)),
|
||||||
|
("short_full_len", compute_message_integrity_full(msg, short_key, false)),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (label, cand) in variants.iter() {
|
||||||
|
if let Some(c) = cand {
|
||||||
|
if c.len() >= 20 && &c[..20] == mi_bytes.as_slice() {
|
||||||
|
warn!("auth accept via MI variant={} username={} realm={} peer={} (interop)", label, username, realm, peer);
|
||||||
|
return AuthStatus::Granted { username, key };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
warn!(
|
warn!(
|
||||||
"auth reject: bad credentials username={} realm={} peer={} a1_md5={} mi_attr={:?} mi_long_adj={:?} mi_long_len={:?} mi_short_adj={:?} mi_short_len={:?}",
|
"auth reject: bad credentials username={} realm={} peer={} a1_md5={} mi_attr={:?} mi_long_adj={:?} mi_long_len={:?} mi_short_adj={:?} mi_short_len={:?} mi_long_full_adj={:?} mi_long_full_len={:?} mi_short_full_adj={:?} mi_short_full_len={:?}",
|
||||||
username,
|
username,
|
||||||
realm,
|
realm,
|
||||||
peer,
|
peer,
|
||||||
@ -226,7 +256,11 @@ impl<S: CredentialStore + Clone> AuthManager<S> {
|
|||||||
mi_long_adj,
|
mi_long_adj,
|
||||||
mi_long_len,
|
mi_long_len,
|
||||||
mi_short_adj,
|
mi_short_adj,
|
||||||
mi_short_len
|
mi_short_len,
|
||||||
|
mi_long_full_adj,
|
||||||
|
mi_long_full_len,
|
||||||
|
mi_short_full_adj,
|
||||||
|
mi_short_full_len
|
||||||
);
|
);
|
||||||
AuthStatus::Reject {
|
AuthStatus::Reject {
|
||||||
code: 401,
|
code: 401,
|
||||||
|
|||||||
27
src/stun.rs
27
src/stun.rs
@ -431,6 +431,33 @@ pub fn compute_message_integrity_len_preserved(msg: &StunMessage, key: &[u8]) ->
|
|||||||
Some(crate::stun::compute_message_integrity(key, &signed))
|
Some(crate::stun::compute_message_integrity(key, &signed))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute MESSAGE-INTEGRITY over the full raw message (including any attributes after MI).
|
||||||
|
/// If `adjust_len` is true, the header length is set to `raw.len() - 20`, otherwise preserved.
|
||||||
|
pub fn compute_message_integrity_full(msg: &StunMessage, key: &[u8], adjust_len: bool) -> Option<Vec<u8>> {
|
||||||
|
let mi = find_message_integrity(msg)?;
|
||||||
|
if mi.value.len() != HMAC_SHA1_LEN {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut signed = msg.raw.clone();
|
||||||
|
if adjust_len {
|
||||||
|
let len = (signed.len() - 20) as u16;
|
||||||
|
let len_bytes = len.to_be_bytes();
|
||||||
|
signed[2] = len_bytes[0];
|
||||||
|
signed[3] = len_bytes[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
let value_start = mi.offset + 4;
|
||||||
|
if value_start + HMAC_SHA1_LEN > signed.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
for b in &mut signed[value_start..value_start + HMAC_SHA1_LEN] {
|
||||||
|
*b = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(crate::stun::compute_message_integrity(key, &signed))
|
||||||
|
}
|
||||||
|
|
||||||
/// Fallback validator: compute MESSAGE-INTEGRITY without adjusting the STUN header length.
|
/// Fallback validator: compute MESSAGE-INTEGRITY without adjusting the STUN header length.
|
||||||
/// Some clients incorrectly leave the header length unchanged when appending FINGERPRINT;
|
/// Some clients incorrectly leave the header length unchanged when appending FINGERPRINT;
|
||||||
/// this matches that behaviour for interop.
|
/// this matches that behaviour for interop.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user