Skip to main content

rtc_stun/
fingerprint.rs

1#[cfg(test)]
2mod fingerprint_test;
3
4use crate::attributes::ATTR_FINGERPRINT;
5use crate::checks::*;
6use crate::message::*;
7use shared::error::*;
8
9use crc::{CRC_32_ISO_HDLC, Crc, Table};
10
11/// FINGERPRINT attribute.
12///
13/// RFC 5389 Section 15.5.
14pub struct FingerprintAttr;
15
16/// Shorthand for FingerprintAttr.
17///
18/// Example:
19///
20///  m := New()
21///  FINGERPRINT.add_to(m).
22pub const FINGERPRINT: FingerprintAttr = FingerprintAttr {};
23
24/// The value the CRC-32 is XORed with, `0x5354554e` — ASCII `STUN`.
25pub const FINGERPRINT_XOR_VALUE: u32 = 0x5354554e;
26/// The attribute's value length in bytes.
27pub const FINGERPRINT_SIZE: usize = 4; // 32 bit
28
29// FingerprintValue returns CRC-32 of b XOR-ed by 0x5354554e.
30//
31// The value of the attribute is computed as the CRC-32 of the STUN message
32// up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with
33// the 32-bit value 0x5354554e (the XOR helps in cases where an
34// application packet is also using CRC-32 in it).
35/// CRC-32 (ISO-HDLC) engine, built once at compile time.
36///
37/// `Crc::new` computes the lookup table; doing that per call made the table
38/// build cost more than the checksum itself for typical ~100-byte STUN
39/// messages (one fingerprint per ICE connectivity check / consent probe).
40static CRC_32: Crc<u32, Table<16>> = Crc::<u32, Table<16>>::new(&CRC_32_ISO_HDLC);
41
42/// Computes the `FINGERPRINT` value over `b`: CRC-32 XORed with [`FINGERPRINT_XOR_VALUE`].
43pub fn fingerprint_value(b: &[u8]) -> u32 {
44    let checksum = CRC_32.checksum(b);
45    checksum ^ FINGERPRINT_XOR_VALUE // XOR
46}
47
48impl Setter for FingerprintAttr {
49    // add_to adds fingerprint to message.
50    fn add_to(&self, m: &mut Message) -> Result<()> {
51        let l = m.length;
52        // length in header should include size of fingerprint attribute
53        m.length += (FINGERPRINT_SIZE + ATTRIBUTE_HEADER_SIZE) as u32; // increasing length
54        m.write_length(); // writing Length to Raw
55        let val = fingerprint_value(&m.raw);
56        let b = val.to_be_bytes();
57        m.length = l;
58        m.add(ATTR_FINGERPRINT, &b);
59        Ok(())
60    }
61}
62
63impl FingerprintAttr {
64    /// Check reads fingerprint value from m and checks it, returning error if any.
65    /// Can return *AttrLengthErr, ErrAttributeNotFound, and *CRCMismatch.
66    pub fn check(&self, m: &Message) -> Result<()> {
67        let b = m.get(ATTR_FINGERPRINT)?;
68        check_size(ATTR_FINGERPRINT, b.len(), FINGERPRINT_SIZE)?;
69        let val = u32::from_be_bytes([b[0], b[1], b[2], b[3]]);
70        let attr_start = m.raw.len() - (FINGERPRINT_SIZE + ATTRIBUTE_HEADER_SIZE);
71        let expected = fingerprint_value(&m.raw[..attr_start]);
72        check_fingerprint(val, expected)
73    }
74}