webrtc_stun/
fingerprint.rs

1#[cfg(test)]
2mod fingerprint_test;
3
4use crate::attributes::ATTR_FINGERPRINT;
5use crate::checks::*;
6use crate::message::*;
7
8use util::Error;
9
10use crc32fast::Hasher;
11
12// FingerprintAttr represents FINGERPRINT attribute.
13//
14// RFC 5389 Section 15.5
15pub struct FingerprintAttr;
16
17// FINGERPRINT is shorthand for FingerprintAttr.
18//
19// Example:
20//
21//  m := New()
22//  FINGERPRINT.add_to(m)
23pub const FINGERPRINT: FingerprintAttr = FingerprintAttr {};
24
25const FINGERPRINT_XOR_VALUE: u32 = 0x5354554e;
26const FINGERPRINT_SIZE: usize = 4; // 32 bit
27
28// FingerprintValue returns CRC-32 of b XOR-ed by 0x5354554e.
29//
30// The value of the attribute is computed as the CRC-32 of the STUN message
31// up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with
32// the 32-bit value 0x5354554e (the XOR helps in cases where an
33// application packet is also using CRC-32 in it).
34pub fn fingerprint_value(b: &[u8]) -> u32 {
35    let mut hasher = Hasher::new();
36    hasher.update(b);
37    let checksum = hasher.finalize();
38    checksum ^ FINGERPRINT_XOR_VALUE // XOR
39}
40
41impl Setter for FingerprintAttr {
42    // add_to adds fingerprint to message.
43    fn add_to(&self, m: &mut Message) -> Result<(), Error> {
44        let l = m.length;
45        // length in header should include size of fingerprint attribute
46        m.length += (FINGERPRINT_SIZE + ATTRIBUTE_HEADER_SIZE) as u32; // increasing length
47        m.write_length(); // writing Length to Raw
48        let val = fingerprint_value(&m.raw);
49        let b = val.to_be_bytes();
50        m.length = l;
51        m.add(ATTR_FINGERPRINT, &b);
52        Ok(())
53    }
54}
55
56impl FingerprintAttr {
57    // Check reads fingerprint value from m and checks it, returning error if any.
58    // Can return *AttrLengthErr, ErrAttributeNotFound, and *CRCMismatch.
59    pub fn check(&self, m: &Message) -> Result<(), Error> {
60        let b = m.get(ATTR_FINGERPRINT)?;
61        check_size(ATTR_FINGERPRINT, b.len(), FINGERPRINT_SIZE)?;
62        let val = u32::from_be_bytes([b[0], b[1], b[2], b[3]]);
63        let attr_start = m.raw.len() - (FINGERPRINT_SIZE + ATTRIBUTE_HEADER_SIZE);
64        let expected = fingerprint_value(&m.raw[..attr_start]);
65        check_fingerprint(val, expected)
66    }
67}