1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::io::{Cursor, Write};
pub use super::errors::{IntegrityKeyGenerationError, MessageDecodeError, MessageEncodeError};
use super::message::StunMessage;
use crate::attribute::StunAttribute;
impl StunMessage {
pub fn encode(&self, integrity_password: Option<&str>) -> Result<Vec<u8>, MessageEncodeError> {
let attr_count = self.attributes.len();
let mut cursor = Cursor::new(Vec::new());
let encoded_header = &self.header.encode()?;
cursor.write_all(encoded_header)?;
let mut msg_integrity_present = false;
let mut username = None;
let mut realm = None;
for (idx, attr) in self.attributes.clone().iter().enumerate() {
let processed_attr = match attr {
StunAttribute::Username { value } => {
username = Some(value.clone());
attr.clone()
}
StunAttribute::Realm { value } => {
realm = Some(value.clone());
attr.clone()
}
StunAttribute::Fingerprint { value } => {
if attr_count - 1 != idx {
return Err(MessageEncodeError::IncorrectFingerprintAttributePosition {
attr_count,
fingerprint_attr_idx: idx,
});
}
if *value == 0 {
self.set_message_length(&mut cursor.get_mut(), 8);
let fingerprint = Self::calculate_fingerprint(cursor.get_ref());
StunAttribute::Fingerprint { value: fingerprint }
} else {
attr.clone()
}
}
StunAttribute::MessageIntegrity { key } => {
msg_integrity_present = true;
if key.is_empty() {
if let Some(integrity_password) = integrity_password {
let integrity_key = Self::calculate_integrity_key(
integrity_password,
realm.clone(),
username.clone(),
)?;
let hmac =
Self::calculate_integrity_hash(&integrity_key, cursor.get_ref());
StunAttribute::MessageIntegrity { key: hmac }
} else {
return Err(MessageEncodeError::MissingIntegrityPassword());
}
} else {
attr.clone()
}
}
_ => {
if msg_integrity_present {
return Err(MessageEncodeError::AttributeAfterIntegrity());
}
attr.clone()
}
};
let encoded_attr = processed_attr.encode(self.header.transaction_id)?;
cursor.write_all(&encoded_attr)?;
}
self.set_message_length(&mut cursor.get_mut(), 0);
Ok(cursor.get_ref().to_vec())
}
}