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}