1use std::collections::HashMap;
88use std::convert::TryFrom;
89use std::sync::{Mutex, OnceLock};
90
91use byteorder::{BigEndian, ByteOrder};
92
93use crate::attribute::*;
94
95use tracing::{debug, warn};
96
97pub const MAGIC_COOKIE: u32 = 0x2112A442;
99
100#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
102pub struct Method(u16);
103
104impl std::fmt::Display for Method {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
107 }
108}
109
110static METHOD_NAME_MAP: OnceLock<Mutex<HashMap<Method, &'static str>>> = OnceLock::new();
111
112impl Method {
113 pub fn add_name(self, name: &'static str) {
115 let mut mnames = METHOD_NAME_MAP
116 .get_or_init(Default::default)
117 .lock()
118 .unwrap();
119 mnames.insert(self, name);
120 }
121
122 pub const fn new(val: u16) -> Self {
134 if val >= 0xf000 {
135 panic!("Method value is out of range!");
136 }
137 Self(val)
138 }
139
140 pub fn value(&self) -> u16 {
150 self.0
151 }
152
153 pub fn name(self) -> &'static str {
161 match self {
162 BINDING => "BINDING",
163 _ => {
164 let mnames = METHOD_NAME_MAP
165 .get_or_init(Default::default)
166 .lock()
167 .unwrap();
168 if let Some(name) = mnames.get(&self) {
169 name
170 } else {
171 "unknown"
172 }
173 }
174 }
175 }
176}
177
178pub const BINDING: Method = Method::new(0x0001);
181
182#[derive(Debug, thiserror::Error)]
184#[non_exhaustive]
185pub enum StunParseError {
186 #[error("The provided data is not a STUN message")]
188 NotStun,
189 #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
191 Truncated {
192 expected: usize,
194 actual: usize,
196 },
197 #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
199 TooLarge {
200 expected: usize,
202 actual: usize,
204 },
205 #[error("Integrity value does not match")]
207 IntegrityCheckFailed,
208 #[error("Missing attribute {:?}", .0)]
210 MissingAttribute(AttributeType),
211 #[error("An attribute {:?} was encountered after a message integrity attribute", .0)]
213 AttributeAfterIntegrity(AttributeType),
214 #[error("An attribute {:?} was encountered after a fingerprint attribute", .0)]
216 AttributeAfterFingerprint(AttributeType),
217 #[error("Fingerprint does not match")]
219 FingerprintMismatch,
220 #[error("The provided data does not match the message")]
222 DataMismatch,
223 #[error("The attribute contains invalid data")]
225 InvalidAttributeData,
226 #[error("Cannot parse with this attribute")]
228 WrongAttributeImplementation,
229}
230
231#[derive(Debug, thiserror::Error)]
233#[non_exhaustive]
234pub enum StunWriteError {
235 #[error("The attribute already exists in the message")]
237 AttributeExists(AttributeType),
238 #[error("The message already contains a fingerprint attribute")]
240 FingerprintExists,
241 #[error("The message already contains a message intregrity attribute")]
243 MessageIntegrityExists,
244 #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
246 TooLarge {
247 expected: usize,
249 actual: usize,
251 },
252 #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
254 TooSmall {
255 expected: usize,
257 actual: usize,
259 },
260 #[error("Failed to compute integrity")]
262 IntegrityFailed,
263 #[error("Out of range input provided")]
265 OutOfRange {
266 value: usize,
268 min: usize,
270 max: usize,
272 },
273}
274
275#[derive(Debug, Clone, PartialEq, Eq)]
277#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
278pub struct LongTermCredentials {
279 username: String,
280 password: String,
281 realm: String,
282}
283
284impl LongTermCredentials {
285 pub fn new(username: String, password: String, realm: String) -> Self {
301 Self {
302 username,
303 password,
304 realm,
305 }
306 }
307
308 pub fn username(&self) -> &str {
310 &self.username
311 }
312
313 pub fn password(&self) -> &str {
315 &self.password
316 }
317
318 pub fn realm(&self) -> &str {
320 &self.realm
321 }
322}
323
324#[derive(Debug, Clone, PartialEq, Eq)]
326#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
327pub struct ShortTermCredentials {
328 password: String,
329}
330
331impl ShortTermCredentials {
332 pub fn new(password: String) -> Self {
342 Self { password }
343 }
344
345 pub fn password(&self) -> &str {
347 &self.password
348 }
349}
350
351#[derive(Debug, Clone, PartialEq, Eq)]
355#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
356pub enum MessageIntegrityCredentials {
357 ShortTerm(ShortTermCredentials),
359 LongTerm(LongTermCredentials),
361}
362
363impl From<LongTermCredentials> for MessageIntegrityCredentials {
364 fn from(value: LongTermCredentials) -> Self {
365 MessageIntegrityCredentials::LongTerm(value)
366 }
367}
368
369impl From<ShortTermCredentials> for MessageIntegrityCredentials {
370 fn from(value: ShortTermCredentials) -> Self {
371 MessageIntegrityCredentials::ShortTerm(value)
372 }
373}
374
375impl MessageIntegrityCredentials {
376 fn make_hmac_key(&self) -> Vec<u8> {
377 match self {
378 MessageIntegrityCredentials::ShortTerm(short) => short.password.clone().into(),
379 MessageIntegrityCredentials::LongTerm(long) => {
380 use md5::{Digest, Md5};
381 let data = long.username.clone()
382 + ":"
383 + &long.realm.clone()
384 + ":"
385 + &long.password.clone();
386 let mut digest = Md5::new();
387 digest.update(&data);
388 digest.finalize().to_vec()
389 }
390 }
391 }
392}
393
394#[derive(Copy, Clone, Debug, PartialEq, Eq)]
406pub enum MessageClass {
407 Request,
409 Indication,
411 Success,
413 Error,
415}
416
417impl MessageClass {
418 pub fn is_response(self) -> bool {
421 matches!(self, MessageClass::Success | MessageClass::Error)
422 }
423
424 fn to_bits(self) -> u16 {
425 match self {
426 MessageClass::Request => 0x000,
427 MessageClass::Indication => 0x010,
428 MessageClass::Success => 0x100,
429 MessageClass::Error => 0x110,
430 }
431 }
432}
433
434#[derive(Copy, Clone, Debug, PartialEq, Eq)]
436pub struct MessageType(u16);
437
438impl std::fmt::Display for MessageType {
439 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
440 write!(
441 f,
442 "MessageType(class: {:?}, method: {}",
443 self.class(),
444 self.method(),
445 )
446 }
447}
448
449impl MessageType {
450 pub fn from_class_method(class: MessageClass, method: Method) -> Self {
461 let class_bits = MessageClass::to_bits(class);
462 let method = method.value();
463 let method_bits = method & 0xf | (method & 0x70) << 1 | (method & 0xf80) << 2;
464 Self(class_bits | method_bits)
467 }
468
469 pub fn class(self) -> MessageClass {
479 let class = (self.0 & 0x10) >> 4 | (self.0 & 0x100) >> 7;
480 match class {
481 0x0 => MessageClass::Request,
482 0x1 => MessageClass::Indication,
483 0x2 => MessageClass::Success,
484 0x3 => MessageClass::Error,
485 _ => unreachable!(),
486 }
487 }
488
489 pub fn has_class(self, cls: MessageClass) -> bool {
499 self.class() == cls
500 }
501
502 pub fn is_response(self) -> bool {
518 self.class().is_response()
519 }
520
521 pub fn method(self) -> Method {
531 Method::new(self.0 & 0xf | (self.0 & 0xe0) >> 1 | (self.0 & 0x3e00) >> 2)
532 }
533
534 pub fn has_method(self, method: Method) -> bool {
544 self.method() == method
545 }
546
547 pub fn write_into(&self, dest: &mut [u8]) {
549 BigEndian::write_u16(dest, self.0);
550 }
551
552 pub fn to_bytes(self) -> Vec<u8> {
554 let mut ret = vec![0; 2];
555 BigEndian::write_u16(&mut ret[0..2], self.0);
556 ret
557 }
558
559 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
561 let data = BigEndian::read_u16(data);
562 if data & 0xc000 != 0x0 {
563 return Err(StunParseError::NotStun);
565 }
566 Ok(Self(data))
567 }
568}
569impl TryFrom<&[u8]> for MessageType {
570 type Error = StunParseError;
571
572 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
573 MessageType::from_bytes(value)
574 }
575}
576
577#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
579pub struct TransactionId {
580 id: u128,
581}
582
583impl TransactionId {
584 pub fn generate() -> TransactionId {
586 use rand::Rng;
587 let mut rng = rand::rng();
588 rng.random::<u128>().into()
589 }
590}
591
592impl From<u128> for TransactionId {
593 fn from(id: u128) -> Self {
594 Self {
595 id: id & 0xffff_ffff_ffff_ffff_ffff_ffff,
596 }
597 }
598}
599impl From<TransactionId> for u128 {
600 fn from(id: TransactionId) -> Self {
601 id.id
602 }
603}
604impl std::fmt::Display for TransactionId {
605 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
606 write!(f, "{:#x}", self.id)
607 }
608}
609
610#[derive(Debug)]
614pub struct MessageHeader {
615 mtype: MessageType,
616 transaction_id: TransactionId,
617 length: u16,
618}
619
620impl MessageHeader {
621 pub const LENGTH: usize = 20;
623
624 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
637 if data.len() < 20 {
638 return Err(StunParseError::Truncated {
639 expected: 20,
640 actual: data.len(),
641 });
642 }
643 let mtype = MessageType::from_bytes(data)?;
644 let mlength = BigEndian::read_u16(&data[2..]);
645 let tid = BigEndian::read_u128(&data[4..]);
646 let cookie = (tid >> 96) as u32;
647 if cookie != MAGIC_COOKIE {
648 warn!(
649 "malformed cookie constant {:?} != stored data {:?}",
650 MAGIC_COOKIE, cookie
651 );
652 return Err(StunParseError::NotStun);
653 }
654
655 Ok(Self {
656 mtype,
657 transaction_id: tid.into(),
658 length: mlength,
659 })
660 }
661
662 pub fn data_length(&self) -> u16 {
665 self.length
666 }
667
668 pub fn transaction_id(&self) -> TransactionId {
670 self.transaction_id
671 }
672
673 pub fn get_type(&self) -> MessageType {
675 self.mtype
676 }
677
678 fn new(mtype: MessageType, transaction_id: TransactionId, length: u16) -> Self {
679 Self {
680 mtype,
681 transaction_id,
682 length,
683 }
684 }
685
686 fn write_into(&self, dest: &mut [u8]) {
687 self.mtype.write_into(&mut dest[..2]);
688 let transaction: u128 = self.transaction_id.into();
689 let tid = (MAGIC_COOKIE as u128) << 96 | transaction & 0xffff_ffff_ffff_ffff_ffff_ffff;
690 BigEndian::write_u128(&mut dest[4..20], tid);
691 BigEndian::write_u16(&mut dest[2..4], self.length);
692 }
693}
694
695#[derive(Debug, Clone)]
700pub struct Message<'a> {
701 data: &'a [u8],
702}
703
704impl std::fmt::Display for Message<'_> {
705 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
706 write!(
707 f,
708 "Message(class: {:?}, method: {}, transaction: {}, attributes: ",
709 self.get_type().class(),
710 self.get_type().method(),
711 self.transaction_id()
712 )?;
713 let iter = self.iter_attributes();
714 write!(f, "[")?;
715 for (i, (_offset, a)) in iter.enumerate() {
716 if i > 0 {
717 write!(f, ", ")?;
718 }
719 write!(f, "{a}")?;
720 }
721 write!(f, "]")?;
722 write!(f, ")")
723 }
724}
725
726#[derive(Clone, Copy, Debug, PartialEq, Eq)]
728pub enum IntegrityAlgorithm {
729 Sha1,
731 Sha256,
733}
734
735impl<'a> Message<'a> {
736 pub fn builder<B: MessageWrite>(
752 mtype: MessageType,
753 transaction_id: TransactionId,
754 mut write: B,
755 ) -> B {
756 let mut data = [0; 20];
757 MessageHeader::new(mtype, transaction_id, 0).write_into(&mut data);
758 write.push_data(&data);
759 write
760 }
761
762 pub fn builder_request<B: MessageWrite>(method: Method, write: B) -> B {
776 Message::builder(
777 MessageType::from_class_method(MessageClass::Request, method),
778 TransactionId::generate(),
779 write,
780 )
781 }
782
783 pub fn builder_success<B: MessageWrite>(orig: &Message, write: B) -> B {
803 if !orig.has_class(MessageClass::Request) {
804 panic!(
805 "A success response message was attempted to be created from a non-request message"
806 );
807 }
808 Message::builder(
809 MessageType::from_class_method(MessageClass::Success, orig.method()),
810 orig.transaction_id(),
811 write,
812 )
813 }
814
815 pub fn builder_error<B: MessageWrite>(orig: &Message, write: B) -> B {
835 if !orig.has_class(MessageClass::Request) {
836 panic!(
837 "An error response message was attempted to be created from a non-request message"
838 );
839 }
840 Message::builder(
841 MessageType::from_class_method(MessageClass::Error, orig.method()),
842 orig.transaction_id(),
843 write,
844 )
845 }
846
847 pub fn get_type(&self) -> MessageType {
861 MessageType::try_from(&self.data[..2]).unwrap()
862 }
863
864 pub fn class(&self) -> MessageClass {
876 self.get_type().class()
877 }
878
879 pub fn has_class(&self, cls: MessageClass) -> bool {
891 self.class() == cls
892 }
893
894 pub fn is_response(&self) -> bool {
916 self.class().is_response()
917 }
918
919 pub fn method(&self) -> Method {
931 self.get_type().method()
932 }
933
934 pub fn has_method(&self, method: Method) -> bool {
947 self.method() == method
948 }
949
950 pub fn transaction_id(&self) -> TransactionId {
964 BigEndian::read_u128(&self.data[4..]).into()
965 }
966
967 #[tracing::instrument(
983 name = "message_from_bytes",
984 level = "trace",
985 skip(data),
986 fields(
987 data.len = data.len()
988 )
989 )]
990 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
991 let orig_data = data;
992
993 let header = MessageHeader::from_bytes(data)?;
994 let mlength = header.data_length() as usize;
995 if mlength + MessageHeader::LENGTH > data.len() {
996 warn!(
998 "malformed advertised size {:?} and data size {:?} don't match",
999 mlength + 20,
1000 data.len()
1001 );
1002 return Err(StunParseError::Truncated {
1003 expected: mlength + MessageHeader::LENGTH,
1004 actual: data.len(),
1005 });
1006 }
1007
1008 let mut data_offset = MessageHeader::LENGTH;
1009 let mut data = &data[MessageHeader::LENGTH..];
1010 let ending_attributes = [
1011 MessageIntegrity::TYPE,
1012 MessageIntegritySha256::TYPE,
1013 Fingerprint::TYPE,
1014 ];
1015 let mut seen_ending_attributes = [AttributeType::new(0); 3];
1017 let mut seen_ending_len = 0;
1018 while !data.is_empty() {
1019 let attr = RawAttribute::from_bytes(data).map_err(|e| {
1020 warn!(
1021 "failed to parse message attribute at offset {data_offset}: {:?}",
1022 e
1023 );
1024 match e {
1025 StunParseError::Truncated { expected, actual } => StunParseError::Truncated {
1026 expected: expected + 4 + data_offset,
1027 actual: actual + 4 + data_offset,
1028 },
1029 StunParseError::TooLarge { expected, actual } => StunParseError::TooLarge {
1030 expected: expected + 4 + data_offset,
1031 actual: actual + 4 + data_offset,
1032 },
1033 e => e,
1034 }
1035 })?;
1036
1037 if seen_ending_len > 0 && !ending_attributes.contains(&attr.get_type()) {
1040 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1041 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1042 return Err(StunParseError::AttributeAfterFingerprint(attr.get_type()));
1043 } else {
1044 warn!(
1046 "unexpected attribute {} after MESSAGE_INTEGRITY",
1047 attr.get_type()
1048 );
1049 return Err(StunParseError::AttributeAfterIntegrity(attr.get_type()));
1050 }
1051 }
1052
1053 if ending_attributes.contains(&attr.get_type()) {
1054 if seen_ending_attributes.contains(&attr.get_type()) {
1055 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1056 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1057 return Err(StunParseError::AttributeAfterFingerprint(attr.get_type()));
1058 } else {
1059 warn!(
1061 "unexpected attribute {} after MESSAGE_INTEGRITY",
1062 attr.get_type()
1063 );
1064 return Err(StunParseError::AttributeAfterIntegrity(attr.get_type()));
1065 }
1066 } else {
1067 seen_ending_attributes[seen_ending_len] = attr.get_type();
1068 seen_ending_len += 1;
1069 }
1071 }
1072 let padded_len = attr.padded_len();
1073 if padded_len > data.len() {
1074 warn!(
1075 "attribute {:?} extends past the end of the data",
1076 attr.get_type()
1077 );
1078 return Err(StunParseError::Truncated {
1079 expected: data_offset + padded_len,
1080 actual: data_offset + data.len(),
1081 });
1082 }
1083 if attr.get_type() == Fingerprint::TYPE {
1084 let f = Fingerprint::from_raw_ref(&attr)?;
1085 let msg_fingerprint = f.fingerprint();
1086 let mut fingerprint_data = orig_data[..data_offset].to_vec();
1087 BigEndian::write_u16(
1088 &mut fingerprint_data[2..4],
1089 (data_offset + padded_len - MessageHeader::LENGTH) as u16,
1090 );
1091 let calculated_fingerprint = Fingerprint::compute(&fingerprint_data);
1092 if &calculated_fingerprint != msg_fingerprint {
1093 warn!(
1094 "fingerprint mismatch {:?} != {:?}",
1095 calculated_fingerprint, msg_fingerprint
1096 );
1097 return Err(StunParseError::FingerprintMismatch);
1098 }
1099 }
1100 data = &data[padded_len..];
1101 data_offset += padded_len;
1102 }
1103 Ok(Message { data: orig_data })
1104 }
1105
1106 #[tracing::instrument(
1129 name = "message_validate_integrity",
1130 level = "trace",
1131 skip(self, credentials),
1132 fields(
1133 msg.transaction = %self.transaction_id(),
1134 )
1135 )]
1136 pub fn validate_integrity(
1137 &self,
1138 credentials: &MessageIntegrityCredentials,
1139 ) -> Result<IntegrityAlgorithm, StunParseError> {
1140 debug!("using credentials {credentials:?}");
1141 let raw_sha1 = self.raw_attribute(MessageIntegrity::TYPE);
1142 let raw_sha256 = self.raw_attribute(MessageIntegritySha256::TYPE);
1143 let (algo, msg_hmac) = match (raw_sha1, raw_sha256) {
1144 (_, Some(sha256)) => {
1145 let integrity = MessageIntegritySha256::try_from(&sha256)?;
1146 (IntegrityAlgorithm::Sha256, integrity.hmac().to_vec())
1147 }
1148 (Some(sha1), None) => {
1149 let integrity = MessageIntegrity::try_from(&sha1)?;
1150 (IntegrityAlgorithm::Sha1, integrity.hmac().to_vec())
1151 }
1152 (None, None) => return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE)),
1153 };
1154
1155 let data = self.data;
1158 debug_assert!(data.len() >= MessageHeader::LENGTH);
1159 let mut data = &data[MessageHeader::LENGTH..];
1160 let mut data_offset = MessageHeader::LENGTH;
1161 while !data.is_empty() {
1162 let attr = RawAttribute::from_bytes(data)?;
1163 if algo == IntegrityAlgorithm::Sha1 && attr.get_type() == MessageIntegrity::TYPE {
1164 let msg = MessageIntegrity::try_from(&attr)?;
1165 debug_assert!(msg.hmac().as_slice() == msg_hmac);
1166
1167 let key = credentials.make_hmac_key();
1170 let mut hmac_data = self.data[..data_offset].to_vec();
1171 BigEndian::write_u16(
1172 &mut hmac_data[2..4],
1173 data_offset as u16 + 24 - MessageHeader::LENGTH as u16,
1174 );
1175 MessageIntegrity::verify(
1176 &hmac_data,
1177 &key,
1178 msg_hmac.as_slice().try_into().unwrap(),
1179 )?;
1180 return Ok(algo);
1181 } else if algo == IntegrityAlgorithm::Sha256
1182 && attr.get_type() == MessageIntegritySha256::TYPE
1183 {
1184 let msg = MessageIntegritySha256::try_from(&attr)?;
1185 debug_assert!(msg.hmac() == msg_hmac);
1186
1187 let key = credentials.make_hmac_key();
1190 let mut hmac_data = self.data[..data_offset].to_vec();
1191 BigEndian::write_u16(
1192 &mut hmac_data[2..4],
1193 data_offset as u16 + attr.padded_len() as u16 - MessageHeader::LENGTH as u16,
1194 );
1195 MessageIntegritySha256::verify(&hmac_data, &key, &msg_hmac)?;
1196 return Ok(algo);
1197 }
1198 let padded_len = attr.padded_len();
1199 debug_assert!(padded_len <= data.len());
1201 data = &data[padded_len..];
1202 data_offset += padded_len;
1203 }
1204
1205 unreachable!();
1208 }
1209
1210 #[tracing::instrument(
1228 name = "message_get_raw_attribute",
1229 level = "trace",
1230 ret,
1231 skip(self, atype),
1232 fields(
1233 msg.transaction = %self.transaction_id(),
1234 attribute_type = %atype,
1235 )
1236 )]
1237 pub fn raw_attribute(&self, atype: AttributeType) -> Option<RawAttribute<'_>> {
1238 self.raw_attribute_and_offset(atype)
1239 .map(|(_offset, attr)| attr)
1240 }
1241
1242 #[tracing::instrument(
1262 name = "message_get_raw_attribute_and_offset",
1263 level = "trace",
1264 ret,
1265 skip(self, atype),
1266 fields(
1267 msg.transaction = %self.transaction_id(),
1268 attribute_type = %atype,
1269 )
1270 )]
1271 pub fn raw_attribute_and_offset(
1272 &self,
1273 atype: AttributeType,
1274 ) -> Option<(usize, RawAttribute<'_>)> {
1275 self.iter_attributes()
1276 .find(|(_offset, attr)| attr.get_type() == atype)
1277 }
1278
1279 #[tracing::instrument(
1301 name = "message_get_attribute",
1302 level = "trace",
1303 ret,
1304 skip(self),
1305 fields(
1306 msg.transaction = %self.transaction_id(),
1307 attribute_type = %A::TYPE,
1308 )
1309 )]
1310 pub fn attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1311 &'a self,
1312 ) -> Result<A, StunParseError> {
1313 self.attribute_and_offset().map(|(_offset, attr)| attr)
1314 }
1315
1316 #[tracing::instrument(
1340 name = "message_get_attribute_and_offset",
1341 level = "trace",
1342 ret,
1343 skip(self),
1344 fields(
1345 msg.transaction = %self.transaction_id(),
1346 attribute_type = %A::TYPE,
1347 )
1348 )]
1349 pub fn attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1350 &'a self,
1351 ) -> Result<(usize, A), StunParseError> {
1352 self.raw_attribute_and_offset(A::TYPE)
1353 .ok_or(StunParseError::MissingAttribute(A::TYPE))
1354 .and_then(|(offset, raw)| A::from_raw(raw).map(|attr| (offset, attr)))
1355 }
1356
1357 pub fn iter_attributes(&self) -> impl Iterator<Item = (usize, RawAttribute<'_>)> {
1359 MessageAttributesIter::new(self.data)
1360 }
1361
1362 #[tracing::instrument(
1410 level = "trace",
1411 skip(msg, write),
1412 fields(
1413 msg.transaction = %msg.transaction_id(),
1414 )
1415 )]
1416 pub fn check_attribute_types<B: MessageWrite>(
1417 msg: &Message,
1418 supported: &[AttributeType],
1419 required_in_msg: &[AttributeType],
1420 write: B,
1421 ) -> Option<B> {
1422 let unsupported: Vec<AttributeType> = msg
1424 .iter_attributes()
1425 .map(|(_offset, a)| a.get_type())
1426 .filter(|at| at.comprehension_required() && !supported.contains(at))
1428 .collect();
1429 if !unsupported.is_empty() {
1430 warn!(
1431 "Message contains unknown comprehension required attributes {:?}, returning unknown attributes",
1432 unsupported
1433 );
1434 return Some(Message::unknown_attributes(msg, &unsupported, write));
1435 }
1436 let has_required_attribute_missing = required_in_msg
1437 .iter()
1438 .any(|&at| {
1440 !msg.iter_attributes()
1441 .map(|(_offset, a)| a.get_type())
1442 .any(|a| a == at)
1443 });
1444 if has_required_attribute_missing {
1445 warn!("Message is missing required attributes, returning bad request");
1446 return Some(Message::bad_request(msg, write));
1447 }
1448 None
1449 }
1450
1451 pub fn unknown_attributes<B: MessageWrite>(
1472 src: &Message,
1473 attributes: &[AttributeType],
1474 write: B,
1475 ) -> B {
1476 let mut out = Message::builder_error(src, write);
1477 let software = Software::new("stun-types").unwrap();
1478 out.add_attribute(&software).unwrap();
1479 let error = ErrorCode::new(420, "Unknown Attributes").unwrap();
1480 out.add_attribute(&error).unwrap();
1481 let unknown = UnknownAttributes::new(attributes);
1482 if !attributes.is_empty() {
1483 out.add_attribute(&unknown).unwrap();
1484 }
1485 out
1486 }
1487
1488 pub fn bad_request<B: MessageWrite>(src: &Message, write: B) -> B {
1506 let mut out = Message::builder_error(src, write);
1507 let software = Software::new("stun-types").unwrap();
1508 out.add_attribute(&software).unwrap();
1509 let error = ErrorCode::new(400, "Bad Request").unwrap();
1510 out.add_attribute(&error).unwrap();
1511 out
1512 }
1513
1514 pub fn has_attribute(&self, atype: AttributeType) -> bool {
1530 self.iter_attributes()
1531 .any(|(_offset, attr)| attr.get_type() == atype)
1532 }
1533}
1534impl<'a> TryFrom<&'a [u8]> for Message<'a> {
1535 type Error = StunParseError;
1536
1537 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
1538 Message::from_bytes(value)
1539 }
1540}
1541
1542#[doc(hidden)]
1543#[derive(Debug)]
1544pub struct MessageAttributesIter<'a> {
1545 data: &'a [u8],
1546 data_i: usize,
1547 last_attr_type: AttributeType,
1548 seen_message_integrity: bool,
1549}
1550
1551impl<'a> MessageAttributesIter<'a> {
1552 pub fn new(data: &'a [u8]) -> Self {
1554 Self {
1555 data,
1556 data_i: MessageHeader::LENGTH,
1557 seen_message_integrity: false,
1558 last_attr_type: AttributeType::new(0),
1559 }
1560 }
1561}
1562
1563impl<'a> Iterator for MessageAttributesIter<'a> {
1564 type Item = (usize, RawAttribute<'a>);
1565
1566 fn next(&mut self) -> Option<Self::Item> {
1567 if self.data_i >= self.data.len() {
1568 return None;
1569 }
1570
1571 let Ok(attr) = RawAttribute::from_bytes(&self.data[self.data_i..]) else {
1572 self.data_i = self.data.len();
1573 return None;
1574 };
1575 let attr_type = attr.get_type();
1576 let padded_len = attr.padded_len();
1577 self.data_i += padded_len;
1578 if self.seen_message_integrity {
1579 if attr_type == Fingerprint::TYPE {
1580 self.last_attr_type = attr_type;
1581 return Some((self.data_i - padded_len, attr));
1582 }
1583 if self.last_attr_type == MessageIntegrity::TYPE
1584 && attr_type == MessageIntegritySha256::TYPE
1585 {
1586 self.last_attr_type = attr_type;
1587 return Some((self.data_i - padded_len, attr));
1588 }
1589 return None;
1590 }
1591 if attr.get_type() == MessageIntegrity::TYPE
1592 || attr.get_type() == MessageIntegritySha256::TYPE
1593 {
1594 self.seen_message_integrity = true;
1595 }
1596 self.last_attr_type = attr.get_type();
1597
1598 Some((self.data_i - padded_len, attr))
1599 }
1600}
1601
1602#[allow(clippy::len_without_is_empty)]
1603pub trait MessageWrite {
1605 type Output;
1607 fn max_size(&self) -> Option<usize> {
1610 None
1611 }
1612
1613 fn mut_data(&mut self) -> &mut [u8];
1615 fn data(&self) -> &[u8];
1617 fn len(&self) -> usize;
1619 fn push_data(&mut self, data: &[u8]);
1621 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite);
1623
1624 fn has_attribute(&self, atype: AttributeType) -> bool {
1626 Message::from_bytes(self.data())
1627 .unwrap()
1628 .has_attribute(atype)
1629 }
1630
1631 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
1634 Message::from_bytes(self.data())
1635 .unwrap()
1636 .iter_attributes()
1637 .find_map(|(_offset, raw)| {
1638 if atypes.contains(&raw.get_type()) {
1639 Some(raw.get_type())
1640 } else {
1641 None
1642 }
1643 })
1644 }
1645
1646 fn finish(self) -> Self::Output;
1648}
1649
1650pub trait MessageWriteExt: MessageWrite {
1652 fn get_type(&self) -> MessageType {
1664 MessageType::from_bytes(self.data()).unwrap()
1665 }
1666
1667 fn class(&self) -> MessageClass {
1679 self.get_type().class()
1680 }
1681
1682 fn has_class(&self, cls: MessageClass) -> bool {
1694 self.class() == cls
1695 }
1696
1697 fn is_response(&self) -> bool {
1719 self.class().is_response()
1720 }
1721
1722 fn method(&self) -> Method {
1734 self.get_type().method()
1735 }
1736
1737 fn has_method(&self, method: Method) -> bool {
1750 self.method() == method
1751 }
1752
1753 fn transaction_id(&self) -> TransactionId {
1767 BigEndian::read_u128(&self.data()[4..]).into()
1768 }
1769
1770 #[tracing::instrument(
1805 name = "message_add_integrity",
1806 level = "trace",
1807 err,
1808 skip(self),
1809 fields(
1810 msg.transaction = %self.transaction_id(),
1811 )
1812 )]
1813 fn add_message_integrity(
1814 &mut self,
1815 credentials: &MessageIntegrityCredentials,
1816 algorithm: IntegrityAlgorithm,
1817 ) -> Result<(), StunWriteError> {
1818 let mut atypes = [AttributeType::new(0); 3];
1819 let mut i = 0;
1820 atypes[i] = match algorithm {
1821 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
1822 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
1823 };
1824 i += 1;
1825 if algorithm == IntegrityAlgorithm::Sha1 {
1826 atypes[i] = MessageIntegritySha256::TYPE;
1827 i += 1;
1828 }
1829 atypes[i] = Fingerprint::TYPE;
1830 i += 1;
1831
1832 match self.has_any_attribute(&atypes[..i]) {
1833 Some(MessageIntegrity::TYPE) => {
1835 return Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
1836 }
1837 Some(MessageIntegritySha256::TYPE) => {
1838 return Err(StunWriteError::AttributeExists(
1839 MessageIntegritySha256::TYPE,
1840 ));
1841 }
1842 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
1843 _ => (),
1844 }
1845 match algorithm {
1846 IntegrityAlgorithm::Sha1 => {
1847 check_attribute_can_fit(self, &MessageIntegrity::new([0; 20]))?
1848 }
1849 IntegrityAlgorithm::Sha256 => {
1850 check_attribute_can_fit(self, &MessageIntegritySha256::new(&[0; 32]).unwrap())?
1851 }
1852 };
1853
1854 add_message_integrity_unchecked(self, credentials, algorithm);
1855
1856 Ok(())
1857 }
1858
1859 #[tracing::instrument(
1877 name = "message_add_fingerprint",
1878 level = "trace",
1879 skip(self),
1880 fields(
1881 msg.transaction = %self.transaction_id(),
1882 )
1883 )]
1884 fn add_fingerprint(&mut self) -> Result<(), StunWriteError> {
1885 if self.has_attribute(Fingerprint::TYPE) {
1886 return Err(StunWriteError::AttributeExists(Fingerprint::TYPE));
1887 }
1888
1889 check_attribute_can_fit(self, &Fingerprint::new([0; 4]))?;
1890 add_fingerprint_unchecked(self);
1891
1892 Ok(())
1893 }
1894
1895 #[tracing::instrument(
1925 name = "message_add_attribute",
1926 level = "trace",
1927 err,
1928 skip(self, attr),
1929 fields(
1930 msg.transaction = %self.transaction_id(),
1931 )
1932 )]
1933 fn add_attribute(&mut self, attr: &dyn AttributeWrite) -> Result<(), StunWriteError> {
1934 let ty = attr.get_type();
1935 match ty {
1937 MessageIntegrity::TYPE => {
1938 panic!("Cannot write MessageIntegrity with `add_attribute`. Use add_message_integrity() instead");
1939 }
1940 MessageIntegritySha256::TYPE => {
1941 panic!("Cannot write MessageIntegritySha256 with `add_attribute`. Use add_message_integrity() instead");
1942 }
1943 Fingerprint::TYPE => {
1944 panic!(
1945 "Cannot write Fingerprint with `add_attribute`. Use add_fingerprint() instead"
1946 );
1947 }
1948 _ => (),
1949 }
1950 match self.has_any_attribute(&[
1951 ty,
1952 MessageIntegrity::TYPE,
1953 MessageIntegritySha256::TYPE,
1954 Fingerprint::TYPE,
1955 ]) {
1956 Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
1958 Some(MessageIntegritySha256::TYPE) => {
1959 return Err(StunWriteError::MessageIntegrityExists)
1960 }
1961 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
1962 Some(typ) if typ == ty => return Err(StunWriteError::AttributeExists(ty)),
1963 _ => (),
1964 }
1965 check_attribute_can_fit(self, attr)?;
1966 self.push_attribute_unchecked(attr);
1967 Ok(())
1968 }
1969}
1970
1971impl<T: MessageWrite> MessageWriteExt for T {}
1972
1973#[derive(Debug, Default)]
1975pub struct MessageWriteVec {
1976 output: Vec<u8>,
1977 attributes: smallvec::SmallVec<[AttributeType; 16]>,
1978}
1979
1980impl MessageWriteVec {
1981 pub fn new() -> Self {
1983 Self::default()
1984 }
1985
1986 pub fn with_capacity(capacity: usize) -> Self {
1988 Self {
1989 output: Vec::with_capacity(capacity),
1990 attributes: Default::default(),
1991 }
1992 }
1993}
1994
1995impl std::ops::Deref for MessageWriteVec {
1996 type Target = Vec<u8>;
1997 fn deref(&self) -> &Self::Target {
1998 &self.output
1999 }
2000}
2001
2002impl std::ops::DerefMut for MessageWriteVec {
2003 fn deref_mut(&mut self) -> &mut Self::Target {
2004 &mut self.output
2005 }
2006}
2007
2008impl MessageWrite for MessageWriteVec {
2009 type Output = Vec<u8>;
2010
2011 fn mut_data(&mut self) -> &mut [u8] {
2012 &mut self.output
2013 }
2014
2015 fn data(&self) -> &[u8] {
2016 &self.output
2017 }
2018
2019 fn len(&self) -> usize {
2020 self.output.len()
2021 }
2022
2023 fn push_data(&mut self, data: &[u8]) {
2024 self.output.extend(data)
2025 }
2026
2027 fn finish(self) -> Self::Output {
2028 self.output
2029 }
2030
2031 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2032 let offset = self.output.len();
2033 let padded_len = attr.padded_len();
2034 let expected = offset + padded_len;
2035 BigEndian::write_u16(
2036 &mut self.output[2..4],
2037 (expected - MessageHeader::LENGTH) as u16,
2038 );
2039 self.output.resize(expected, 0);
2040 attr.write_into_unchecked(&mut self.output[offset..]);
2041 self.attributes.push(attr.get_type());
2042 }
2043
2044 fn has_attribute(&self, atype: AttributeType) -> bool {
2045 self.attributes.contains(&atype)
2046 }
2047
2048 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2049 self.attributes
2050 .iter()
2051 .find(|&typ| atypes.contains(typ))
2052 .cloned()
2053 }
2054}
2055
2056#[derive(Debug, Default)]
2058pub struct MessageWriteMutSlice<'a> {
2059 output: &'a mut [u8],
2060 offset: usize,
2061 attributes: smallvec::SmallVec<[AttributeType; 16]>,
2062}
2063
2064impl<'a> MessageWriteMutSlice<'a> {
2065 pub fn new(data: &'a mut [u8]) -> Self {
2067 Self {
2068 output: data,
2069 offset: 0,
2070 attributes: Default::default(),
2071 }
2072 }
2073}
2074
2075impl std::ops::Deref for MessageWriteMutSlice<'_> {
2076 type Target = [u8];
2077 fn deref(&self) -> &Self::Target {
2078 self.output
2079 }
2080}
2081
2082impl std::ops::DerefMut for MessageWriteMutSlice<'_> {
2083 fn deref_mut(&mut self) -> &mut Self::Target {
2084 self.output
2085 }
2086}
2087
2088impl<'a> MessageWrite for MessageWriteMutSlice<'a> {
2089 type Output = usize;
2090
2091 fn max_size(&self) -> Option<usize> {
2092 Some(self.output.len())
2093 }
2094
2095 fn mut_data(&mut self) -> &mut [u8] {
2096 &mut self.output[..self.offset]
2097 }
2098
2099 fn data(&self) -> &[u8] {
2100 &self.output[..self.offset]
2101 }
2102
2103 fn len(&self) -> usize {
2104 self.offset
2105 }
2106
2107 fn push_data(&mut self, data: &[u8]) {
2108 let len = data.len();
2109 self.output[self.offset..self.offset + len].copy_from_slice(data);
2110 self.offset += len;
2111 }
2112
2113 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2114 let padded_len = attr.padded_len();
2115 let expected = self.offset + padded_len;
2116 BigEndian::write_u16(
2117 &mut self.output[2..4],
2118 (expected - MessageHeader::LENGTH) as u16,
2119 );
2120 attr.write_into(&mut self.output[self.offset..self.offset + padded_len])
2121 .unwrap();
2122 self.offset += padded_len;
2123 }
2124
2125 fn finish(self) -> Self::Output {
2126 self.offset
2127 }
2128
2129 fn has_attribute(&self, atype: AttributeType) -> bool {
2130 self.attributes.contains(&atype)
2131 }
2132
2133 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2134 self.attributes
2135 .iter()
2136 .find(|&typ| atypes.contains(typ))
2137 .cloned()
2138 }
2139}
2140
2141fn check_attribute_can_fit<O, T: MessageWrite<Output = O> + ?Sized>(
2142 this: &mut T,
2143 attr: &dyn AttributeWrite,
2144) -> Result<usize, StunWriteError> {
2145 let len = attr.padded_len();
2146 let out_data = this.data();
2147 if out_data.len() < MessageHeader::LENGTH {
2148 return Err(StunWriteError::TooSmall {
2149 expected: 20,
2150 actual: out_data.len(),
2151 });
2152 }
2153 let expected = BigEndian::read_u16(&out_data[2..4]) as usize + MessageHeader::LENGTH + len;
2154 if let Some(max) = this.max_size() {
2155 if max < expected {
2156 return Err(StunWriteError::TooSmall {
2157 expected,
2158 actual: max,
2159 });
2160 }
2161 }
2162 Ok(expected)
2163}
2164
2165fn add_message_integrity_unchecked<O, T: MessageWrite<Output = O> + ?Sized>(
2166 this: &mut T,
2167 credentials: &MessageIntegrityCredentials,
2168 algorithm: IntegrityAlgorithm,
2169) {
2170 let key = credentials.make_hmac_key();
2171 match algorithm {
2174 IntegrityAlgorithm::Sha1 => {
2175 this.push_attribute_unchecked(&MessageIntegrity::new([0; 20]));
2176 let len = this.len();
2177 let data = this.mut_data();
2178 let integrity = MessageIntegrity::compute(&data[..len - 24], &key).unwrap();
2179 data[len - 20..].copy_from_slice(&integrity);
2180 }
2181 IntegrityAlgorithm::Sha256 => {
2182 this.push_attribute_unchecked(&MessageIntegritySha256::new(&[0; 32]).unwrap());
2183 let len = this.len();
2184 let data = this.mut_data();
2185 let integrity = MessageIntegritySha256::compute(&data[..len - 36], &key).unwrap();
2186 data[len - 32..].copy_from_slice(&integrity);
2187 }
2188 }
2189}
2190
2191fn add_fingerprint_unchecked<O, T: MessageWrite<Output = O> + ?Sized>(this: &mut T) {
2192 this.push_attribute_unchecked(&Fingerprint::new([0; 4]));
2195 let len = this.len();
2196 let data = this.mut_data();
2197 let fingerprint = Fingerprint::compute(&data[..len - 8]);
2198 let fingerprint = Fingerprint::new(fingerprint);
2199 fingerprint.write_into(&mut data[len - 8..]).unwrap();
2200}
2201
2202#[cfg(test)]
2203mod tests {
2204 use super::*;
2205
2206 #[test]
2207 fn msg_type_roundtrip() {
2208 let _log = crate::tests::test_init_log();
2209 for m in 0..0xfff {
2211 let m = Method::new(m);
2212 let classes = vec![
2213 MessageClass::Request,
2214 MessageClass::Indication,
2215 MessageClass::Success,
2216 MessageClass::Error,
2217 ];
2218 for c in classes {
2219 let mtype = MessageType::from_class_method(c, m);
2220 assert_eq!(mtype.class(), c);
2221 assert_eq!(mtype.method(), m);
2222 let bytes = mtype.to_bytes();
2223 let ptype = MessageType::from_bytes(&bytes).unwrap();
2224 assert_eq!(mtype, ptype);
2225 }
2226 }
2227 }
2228
2229 #[test]
2230 fn msg_type_not_stun() {
2231 assert!(matches!(
2232 MessageType::from_bytes(&[0xc0, 0x00]),
2233 Err(StunParseError::NotStun)
2234 ));
2235 }
2236
2237 #[test]
2238 fn msg_roundtrip() {
2239 let _log = crate::tests::test_init_log();
2240 for m in (0x009..0x4ff).step_by(0x123) {
2242 let m = Method::new(m);
2243 let classes = vec![
2244 MessageClass::Request,
2245 MessageClass::Indication,
2246 MessageClass::Success,
2247 MessageClass::Error,
2248 ];
2249 for c in classes {
2250 let mtype = MessageType::from_class_method(c, m);
2251 for tid in (0x18..0xff_ffff_ffff_ffff_ffff).step_by(0xfedc_ba98_7654_3210) {
2252 let mut msg = Message::builder(mtype, tid.into(), MessageWriteVec::default());
2253 let attr = RawAttribute::new(1.into(), &[3]);
2254 assert!(msg.add_attribute(&attr).is_ok());
2255 let data = msg.finish();
2256
2257 let msg = Message::from_bytes(&data).unwrap();
2258 let msg_attr = msg.raw_attribute(1.into()).unwrap();
2259 assert_eq!(msg_attr, attr);
2260 assert_eq!(msg.get_type(), mtype);
2261 assert_eq!(msg.transaction_id(), tid.into());
2262 }
2263 }
2264 }
2265 }
2266
2267 #[test]
2268 fn unknown_attributes() {
2269 let _log = crate::tests::test_init_log();
2270 let src = Message::builder_request(BINDING, MessageWriteVec::default()).finish();
2271 let src = Message::from_bytes(&src).unwrap();
2272 let msg =
2273 Message::unknown_attributes(&src, &[Software::TYPE], MessageWriteVec::new()).finish();
2274 let msg = Message::from_bytes(&msg).unwrap();
2275 assert_eq!(msg.transaction_id(), src.transaction_id());
2276 assert_eq!(msg.class(), MessageClass::Error);
2277 assert_eq!(msg.method(), src.method());
2278 let err = msg.attribute::<ErrorCode>().unwrap();
2279 assert_eq!(err.code(), 420);
2280 let unknown_attrs = msg.attribute::<UnknownAttributes>().unwrap();
2281 assert!(unknown_attrs.has_attribute(Software::TYPE));
2282 }
2283
2284 #[test]
2285 fn bad_request() {
2286 let _log = crate::tests::test_init_log();
2287 let src = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2288 let src = Message::from_bytes(&src).unwrap();
2289 let msg = Message::bad_request(&src, MessageWriteVec::new()).finish();
2290 let msg = Message::from_bytes(&msg).unwrap();
2291 assert_eq!(msg.transaction_id(), src.transaction_id());
2292 assert_eq!(msg.class(), MessageClass::Error);
2293 assert_eq!(msg.method(), src.method());
2294 let err = msg.attribute::<ErrorCode>().unwrap();
2295 assert_eq!(err.code(), 400);
2296 }
2297
2298 #[test]
2299 fn fingerprint() {
2300 let _log = crate::tests::test_init_log();
2301 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2302 let software = Software::new("s").unwrap();
2303 msg.add_attribute(&software).unwrap();
2304 msg.add_fingerprint().unwrap();
2305 let bytes = msg.finish();
2306 let new_msg = Message::from_bytes(&bytes).unwrap();
2308 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2309 assert_eq!(software.software(), "s");
2310 assert_eq!(offset, 20);
2311 let (offset, _new_fingerprint) = new_msg.attribute_and_offset::<Fingerprint>().unwrap();
2312 assert_eq!(offset, 28);
2313 }
2314
2315 #[test]
2316 fn integrity() {
2317 let _log = crate::tests::test_init_log();
2318 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2319 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2320 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2321 let software = Software::new("s").unwrap();
2322 msg.add_attribute(&software).unwrap();
2323 msg.add_message_integrity(&credentials, algorithm).unwrap();
2324 let bytes = msg.finish();
2325 let new_msg = Message::from_bytes(&bytes).unwrap();
2327 new_msg.validate_integrity(&credentials).unwrap();
2328 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2329 assert_eq!(software.software(), "s");
2330 assert_eq!(offset, 20);
2331 }
2332 }
2333
2334 #[test]
2335 fn write_into_short_destination() {
2336 let _log = crate::tests::test_init_log();
2337 const LEN: usize = MessageHeader::LENGTH + 8;
2338 let mut data = [0; LEN - 1];
2339 let mut msg = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
2340 let software = Software::new("s").unwrap();
2341 assert!(
2342 matches!(msg.add_attribute(&software), Err(StunWriteError::TooSmall { expected, actual }) if expected == LEN && actual == LEN - 1)
2343 );
2344 }
2345
2346 #[test]
2347 fn add_duplicate_integrity() {
2348 let _log = crate::tests::test_init_log();
2349 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2350 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2351 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2352 .unwrap();
2353 assert!(matches!(
2354 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2355 Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2356 ));
2357 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2358 .unwrap();
2359 assert!(matches!(
2360 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256),
2361 Err(StunWriteError::AttributeExists(
2362 MessageIntegritySha256::TYPE
2363 ))
2364 ));
2365 let software = Software::new("s").unwrap();
2366 assert!(matches!(
2367 msg.add_attribute(&software),
2368 Err(StunWriteError::MessageIntegrityExists)
2369 ));
2370 }
2371
2372 #[test]
2373 fn add_sha1_integrity_after_sha256() {
2374 let _log = crate::tests::test_init_log();
2375 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2376 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2377 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2378 .unwrap();
2379 assert!(matches!(
2380 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2381 Err(StunWriteError::AttributeExists(
2382 MessageIntegritySha256::TYPE
2383 ))
2384 ));
2385 }
2386
2387 #[test]
2388 fn add_attribute_after_integrity() {
2389 let _log = crate::tests::test_init_log();
2390 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2391 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2392 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2393 msg.add_message_integrity(&credentials, algorithm).unwrap();
2394 let software = Software::new("s").unwrap();
2395 assert!(matches!(
2396 msg.add_attribute(&software),
2397 Err(StunWriteError::MessageIntegrityExists)
2398 ));
2399 }
2400 }
2401
2402 #[test]
2403 fn add_raw_attribute_after_integrity() {
2404 let _log = crate::tests::test_init_log();
2405 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2406 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2407 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2408 msg.add_message_integrity(&credentials, algorithm).unwrap();
2409 let software = Software::new("s").unwrap();
2410 let raw = software.to_raw();
2411 assert!(matches!(
2412 msg.add_attribute(&raw),
2413 Err(StunWriteError::MessageIntegrityExists)
2414 ));
2415 }
2416 }
2417
2418 #[test]
2419 fn add_integrity_after_fingerprint() {
2420 let _log = crate::tests::test_init_log();
2421 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2422 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2423 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2424 msg.add_fingerprint().unwrap();
2425 assert!(matches!(
2426 msg.add_message_integrity(&credentials, algorithm),
2427 Err(StunWriteError::FingerprintExists)
2428 ));
2429 }
2430 }
2431
2432 #[test]
2433 fn duplicate_add_attribute() {
2434 let _log = crate::tests::test_init_log();
2435 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2436 let software = Software::new("s").unwrap();
2437 msg.add_attribute(&software).unwrap();
2438 assert!(matches!(
2439 msg.add_attribute(&software),
2440 Err(StunWriteError::AttributeExists(ty)) if ty == Software::TYPE
2441 ));
2442 }
2443
2444 #[test]
2445 fn duplicate_add_raw_attribute() {
2446 let _log = crate::tests::test_init_log();
2447 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2448 let software = Software::new("s").unwrap();
2449 let raw = software.to_raw();
2450 msg.add_attribute(&raw).unwrap();
2451 assert!(matches!(
2452 msg.add_attribute(&raw),
2453 Err(StunWriteError::AttributeExists(ty)) if ty == Software::TYPE
2454 ));
2455 }
2456
2457 #[test]
2458 fn duplicate_fingerprint() {
2459 let _log = crate::tests::test_init_log();
2460 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2461 msg.add_fingerprint().unwrap();
2462 assert!(matches!(
2463 msg.add_fingerprint(),
2464 Err(StunWriteError::AttributeExists(Fingerprint::TYPE))
2465 ));
2466 }
2467
2468 #[test]
2469 fn parse_invalid_fingerprint() {
2470 let _log = crate::tests::test_init_log();
2471 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2472 msg.add_fingerprint().unwrap();
2473 let mut bytes = msg.finish();
2474 bytes[24] = 0x80;
2475 bytes[25] = 0x80;
2476 bytes[26] = 0x80;
2477 bytes[27] = 0x80;
2478 assert!(matches!(
2479 Message::from_bytes(&bytes),
2480 Err(StunParseError::FingerprintMismatch)
2481 ));
2482 }
2483
2484 #[test]
2485 fn parse_wrong_magic() {
2486 let _log = crate::tests::test_init_log();
2487 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2488 msg.add_fingerprint().unwrap();
2489 let mut bytes = msg.finish();
2490 bytes[4] = 0x80;
2491 assert!(matches!(
2492 Message::from_bytes(&bytes),
2493 Err(StunParseError::NotStun)
2494 ));
2495 }
2496
2497 #[test]
2498 fn parse_attribute_after_integrity() {
2499 let _log = crate::tests::test_init_log();
2500 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2501 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2502 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2503 msg.add_message_integrity(&credentials, algorithm).unwrap();
2504 let mut bytes = msg.finish();
2505 let software = Software::new("s").unwrap();
2506 let software_bytes = RawAttribute::from(&software).to_bytes();
2507 let software_len = software_bytes.len();
2508 bytes.extend(software_bytes);
2509 bytes[3] += software_len as u8;
2510 assert!(matches!(
2511 Message::from_bytes(&bytes),
2512 Err(StunParseError::AttributeAfterIntegrity(Software::TYPE))
2513 ));
2514 }
2515 }
2516
2517 #[test]
2518 fn parse_duplicate_integrity_after_integrity() {
2519 let _log = crate::tests::test_init_log();
2520 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2521 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2522 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2523 msg.add_message_integrity(&credentials, algorithm).unwrap();
2524 add_message_integrity_unchecked(&mut msg, &credentials, algorithm);
2526 let bytes = msg.finish();
2527 let integrity_type = match algorithm {
2528 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2529 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2530 };
2531 let Err(StunParseError::AttributeAfterIntegrity(err_integrity_type)) =
2532 Message::from_bytes(&bytes)
2533 else {
2534 unreachable!();
2535 };
2536 assert_eq!(integrity_type, err_integrity_type);
2537 }
2538 }
2539
2540 #[test]
2541 fn parse_attribute_after_fingerprint() {
2542 let _log = crate::tests::test_init_log();
2543 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2544 msg.add_fingerprint().unwrap();
2545 let mut bytes = msg.finish();
2546 let software = Software::new("s").unwrap();
2547 let software_bytes = RawAttribute::from(&software).to_bytes();
2548 let software_len = software_bytes.len();
2549 bytes.extend(software_bytes);
2550 bytes[3] += software_len as u8;
2551 assert!(matches!(
2552 Message::from_bytes(&bytes),
2553 Err(StunParseError::AttributeAfterFingerprint(Software::TYPE))
2554 ));
2555 }
2556
2557 #[test]
2558 fn parse_duplicate_fingerprint_after_fingerprint() {
2559 let _log = crate::tests::test_init_log();
2560 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2561 msg.add_fingerprint().unwrap();
2562 add_fingerprint_unchecked(&mut msg);
2563 let bytes = msg.finish();
2564 assert!(matches!(
2565 Message::from_bytes(&bytes),
2566 Err(StunParseError::AttributeAfterFingerprint(Fingerprint::TYPE))
2567 ));
2568 }
2569
2570 #[test]
2571 fn add_attribute_after_fingerprint() {
2572 let _log = crate::tests::test_init_log();
2573 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2574 msg.add_fingerprint().unwrap();
2575 let software = Software::new("s").unwrap();
2576 assert!(matches!(
2577 msg.add_attribute(&software),
2578 Err(StunWriteError::FingerprintExists)
2579 ));
2580 }
2581
2582 #[test]
2583 fn add_raw_attribute_after_fingerprint() {
2584 let _log = crate::tests::test_init_log();
2585 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2586 msg.add_fingerprint().unwrap();
2587 let software = Software::new("s").unwrap();
2588 let raw = software.to_raw();
2589 assert!(matches!(
2590 msg.add_attribute(&raw),
2591 Err(StunWriteError::FingerprintExists)
2592 ));
2593 }
2594
2595 #[test]
2596 fn parse_truncated_message_header() {
2597 let _log = crate::tests::test_init_log();
2598 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2599 msg.add_fingerprint().unwrap();
2600 let bytes = msg.finish();
2601 assert!(matches!(
2602 Message::from_bytes(&bytes[..8]),
2603 Err(StunParseError::Truncated {
2604 expected: 20,
2605 actual: 8
2606 })
2607 ));
2608 }
2609
2610 #[test]
2611 fn parse_truncated_message() {
2612 let _log = crate::tests::test_init_log();
2613 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2614 msg.add_fingerprint().unwrap();
2615 let bytes = msg.finish();
2616 assert!(matches!(
2617 Message::from_bytes(&bytes[..24]),
2618 Err(StunParseError::Truncated {
2619 expected: 28,
2620 actual: 24
2621 })
2622 ));
2623 }
2624
2625 #[test]
2626 fn parse_truncated_message_attribute() {
2627 let _log = crate::tests::test_init_log();
2628 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2629 msg.add_fingerprint().unwrap();
2630 let mut bytes = msg.finish();
2631 bytes[3] = 4;
2633 assert!(matches!(
2634 Message::from_bytes(&bytes[..24]),
2635 Err(StunParseError::Truncated {
2636 expected: 28,
2637 actual: 24
2638 })
2639 ));
2640 }
2641
2642 #[test]
2643 fn valid_attributes() {
2644 let _log = crate::tests::test_init_log();
2645 let mut src = Message::builder_request(BINDING, MessageWriteVec::new());
2646 let username = Username::new("123").unwrap();
2647 src.add_attribute(&username).unwrap();
2648 let priority = Priority::new(123);
2649 src.add_attribute(&priority).unwrap();
2650 let src = src.finish();
2651 let src = Message::from_bytes(&src).unwrap();
2652
2653 let res = Message::check_attribute_types(
2655 &src,
2656 &[Username::TYPE, Priority::TYPE],
2657 &[Username::TYPE],
2658 MessageWriteVec::new(),
2659 );
2660 assert!(res.is_none());
2661
2662 let res = Message::check_attribute_types(
2664 &src,
2665 &[Username::TYPE, Priority::TYPE],
2666 &[Fingerprint::TYPE],
2667 MessageWriteVec::new(),
2668 );
2669 assert!(res.is_some());
2670 let res = res.unwrap();
2671 let res = res.finish();
2672 let res = Message::from_bytes(&res).unwrap();
2673 assert!(res.has_class(MessageClass::Error));
2674 assert!(res.has_method(src.method()));
2675 let err = res.attribute::<ErrorCode>().unwrap();
2676 assert_eq!(err.code(), 400);
2677
2678 let res =
2680 Message::check_attribute_types(&src, &[Username::TYPE], &[], MessageWriteVec::new());
2681 assert!(res.is_some());
2682 let res = res.unwrap();
2683 let data = res.finish();
2684 let res = Message::from_bytes(&data).unwrap();
2685 assert!(res.has_class(MessageClass::Error));
2686 assert!(res.has_method(src.method()));
2687 let err = res.attribute::<ErrorCode>().unwrap();
2688 assert_eq!(err.code(), 420);
2689 let unknown = res.attribute::<UnknownAttributes>().unwrap();
2690 assert!(unknown.has_attribute(Priority::TYPE));
2691 }
2692
2693 #[test]
2694 #[should_panic(expected = "created from a non-request message")]
2695 fn builder_success_panic() {
2696 let _log = crate::tests::test_init_log();
2697 let msg = Message::builder(
2698 MessageType::from_class_method(MessageClass::Indication, BINDING),
2699 TransactionId::generate(),
2700 MessageWriteVec::new(),
2701 )
2702 .finish();
2703 let msg = Message::from_bytes(&msg).unwrap();
2704 let _builder = Message::builder_success(&msg, MessageWriteVec::new());
2705 }
2706
2707 #[test]
2708 #[should_panic(expected = "created from a non-request message")]
2709 fn builder_error_panic() {
2710 let _log = crate::tests::test_init_log();
2711 let msg = Message::builder(
2712 MessageType::from_class_method(MessageClass::Indication, BINDING),
2713 TransactionId::generate(),
2714 MessageWriteVec::new(),
2715 )
2716 .finish();
2717 let msg = Message::from_bytes(&msg).unwrap();
2718 let _builder = Message::builder_error(&msg, MessageWriteVec::new());
2719 }
2720
2721 #[test]
2722 #[should_panic(expected = "Use add_message_integrity() instead")]
2723 fn builder_add_attribute_integrity_panic() {
2724 let _log = crate::tests::test_init_log();
2725 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2726 let hmac = [2; 20];
2727 let integrity = MessageIntegrity::new(hmac);
2728 msg.add_attribute(&integrity).unwrap();
2729 }
2730
2731 #[test]
2732 #[should_panic(expected = "Use add_message_integrity() instead")]
2733 fn builder_add_raw_attribute_integrity_panic() {
2734 let _log = crate::tests::test_init_log();
2735 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2736 let hmac = [2; 20];
2737 let integrity = MessageIntegrity::new(hmac);
2738 let raw = integrity.to_raw();
2739 msg.add_attribute(&raw).unwrap();
2740 }
2741
2742 #[test]
2743 #[should_panic(expected = "Use add_message_integrity() instead")]
2744 fn builder_add_attribute_integrity_sha256_panic() {
2745 let _log = crate::tests::test_init_log();
2746 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2747 let hmac = [2; 16];
2748 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
2749 msg.add_attribute(&integrity).unwrap();
2750 }
2751
2752 #[test]
2753 #[should_panic(expected = "Use add_message_integrity() instead")]
2754 fn builder_add_raw_attribute_integrity_sha256_panic() {
2755 let _log = crate::tests::test_init_log();
2756 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2757 let hmac = [2; 16];
2758 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
2759 let raw = integrity.to_raw();
2760 msg.add_attribute(&raw).unwrap();
2761 }
2762
2763 #[test]
2764 #[should_panic(expected = "Use add_fingerprint() instead")]
2765 fn builder_add_attribute_fingerprint_panic() {
2766 let _log = crate::tests::test_init_log();
2767 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2768 let fingerprint = [2; 4];
2769 let fingerprint = Fingerprint::new(fingerprint);
2770 msg.add_attribute(&fingerprint).unwrap();
2771 }
2772
2773 #[test]
2774 #[should_panic(expected = "Use add_fingerprint() instead")]
2775 fn builder_add_raw_attribute_fingerprint_panic() {
2776 let _log = crate::tests::test_init_log();
2777 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2778 let fingerprint = [2; 4];
2779 let fingerprint = Fingerprint::new(fingerprint);
2780 let raw = fingerprint.to_raw();
2781 msg.add_attribute(&raw).unwrap();
2782 }
2783
2784 #[test]
2785 fn rfc5769_vector1() {
2786 let _log = crate::tests::test_init_log();
2787 let data = vec![
2789 0x00, 0x01, 0x00, 0x58, 0x21, 0x12, 0xa4, 0x42, 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae, 0x80, 0x22, 0x00, 0x10, 0x53, 0x54, 0x55, 0x4e, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x00, 0x24, 0x00, 0x04, 0x6e, 0x00, 0x01, 0xff, 0x80, 0x29, 0x00, 0x08, 0x93, 0x2f, 0xf9, 0xb1, 0x51, 0x26, 0x3b, 0x36, 0x00, 0x06, 0x00, 0x09, 0x65, 0x76, 0x74, 0x6a, 0x3a, 0x68, 0x36, 0x76, 0x59, 0x20, 0x20, 0x20, 0x00, 0x08, 0x00, 0x14, 0x9a, 0xea, 0xa7, 0x0c, 0xbf, 0xd8, 0xcb, 0x56, 0x78, 0x1e, 0xf2, 0xb5, 0xb2, 0xd3, 0xf2, 0x49, 0xc1, 0xb5, 0x71, 0xa2, 0x80, 0x28, 0x00, 0x04, 0xe5, 0x7a, 0x3b, 0xcf, ];
2817 let msg = Message::from_bytes(&data).unwrap();
2818 assert!(msg.has_class(MessageClass::Request));
2819 assert!(msg.has_method(BINDING));
2820 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
2821
2822 let mut builder = Message::builder(
2823 MessageType::from_class_method(MessageClass::Request, BINDING),
2824 msg.transaction_id(),
2825 MessageWriteVec::new(),
2826 );
2827
2828 assert!(msg.has_attribute(Software::TYPE));
2830 let raw = msg.raw_attribute(Software::TYPE).unwrap();
2831 assert!(Software::try_from(&raw).is_ok());
2832 let software = Software::try_from(&raw).unwrap();
2833 assert_eq!(software.software(), "STUN test client");
2834 builder.add_attribute(&software).unwrap();
2835
2836 assert!(msg.has_attribute(Priority::TYPE));
2838 let raw = msg.raw_attribute(Priority::TYPE).unwrap();
2839 assert!(Priority::try_from(&raw).is_ok());
2840 let priority = Priority::try_from(&raw).unwrap();
2841 assert_eq!(priority.priority(), 0x6e0001ff);
2842 builder.add_attribute(&priority).unwrap();
2843
2844 assert!(msg.has_attribute(IceControlled::TYPE));
2846 let raw = msg.raw_attribute(IceControlled::TYPE).unwrap();
2847 assert!(IceControlled::try_from(&raw).is_ok());
2848 let ice = IceControlled::try_from(&raw).unwrap();
2849 assert_eq!(ice.tie_breaker(), 0x932f_f9b1_5126_3b36);
2850 builder.add_attribute(&ice).unwrap();
2851
2852 assert!(msg.has_attribute(Username::TYPE));
2854 let raw = msg.raw_attribute(Username::TYPE).unwrap();
2855 assert!(Username::try_from(&raw).is_ok());
2856 let username = Username::try_from(&raw).unwrap();
2857 assert_eq!(username.username(), "evtj:h6vY");
2858 builder.add_attribute(&username).unwrap();
2859
2860 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
2862 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
2863 });
2864 assert!(matches!(
2865 msg.validate_integrity(&credentials),
2866 Ok(IntegrityAlgorithm::Sha1)
2867 ));
2868 builder
2869 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2870 .unwrap();
2871
2872 assert!(msg.has_attribute(Fingerprint::TYPE));
2874 builder.add_fingerprint().unwrap();
2875
2876 let mut msg_data = builder.finish();
2878 msg_data[73] = 0x20;
2880 msg_data[74] = 0x20;
2881 msg_data[75] = 0x20;
2882 assert_eq!(msg_data[..80], data[..80]);
2885 }
2886
2887 #[test]
2888 fn rfc5769_vector2() {
2889 let _log = crate::tests::test_init_log();
2890 let data = vec![
2892 0x01, 0x01, 0x00, 0x3c, 0x21, 0x12, 0xa4, 0x42, 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae, 0x80, 0x22, 0x00, 0x0b, 0x74, 0x65, 0x73, 0x74, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x00, 0x20, 0x00, 0x08, 0x00, 0x01, 0xa1, 0x47, 0xe1, 0x12, 0xa6, 0x43, 0x00, 0x08, 0x00, 0x14, 0x2b, 0x91, 0xf5, 0x99, 0xfd, 0x9e, 0x90, 0xc3, 0x8c, 0x74, 0x89, 0xf9, 0x2a, 0xf9, 0xba, 0x53, 0xf0, 0x6b, 0xe7, 0xd7, 0x80, 0x28, 0x00, 0x04, 0xc0, 0x7d, 0x4c, 0x96, ];
2913
2914 let msg = Message::from_bytes(&data).unwrap();
2915 assert!(msg.has_class(MessageClass::Success));
2916 assert!(msg.has_method(BINDING));
2917 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
2918 let mut builder = Message::builder(
2919 MessageType::from_class_method(MessageClass::Success, BINDING),
2920 msg.transaction_id(),
2921 MessageWriteVec::new(),
2922 );
2923
2924 assert!(msg.has_attribute(Software::TYPE));
2926 let raw = msg.raw_attribute(Software::TYPE).unwrap();
2927 assert!(Software::try_from(&raw).is_ok());
2928 let software = Software::try_from(&raw).unwrap();
2929 assert_eq!(software.software(), "test vector");
2930 builder.add_attribute(&software).unwrap();
2931
2932 assert!(msg.has_attribute(XorMappedAddress::TYPE));
2934 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
2935 assert!(XorMappedAddress::try_from(&raw).is_ok());
2936 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
2937 assert_eq!(
2938 xor_mapped_addres.addr(msg.transaction_id()),
2939 "192.0.2.1:32853".parse().unwrap()
2940 );
2941 builder.add_attribute(&xor_mapped_addres).unwrap();
2942
2943 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
2945 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
2946 });
2947 let ret = msg.validate_integrity(&credentials);
2948 debug!("{:?}", ret);
2949 assert!(matches!(ret, Ok(IntegrityAlgorithm::Sha1)));
2950 builder
2951 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2952 .unwrap();
2953
2954 assert!(msg.has_attribute(Fingerprint::TYPE));
2956 builder.add_fingerprint().unwrap();
2957
2958 let mut msg_data = builder.finish();
2960 msg_data[35] = 0x20;
2962 assert_eq!(msg_data[..52], data[..52]);
2963 }
2964
2965 #[test]
2966 fn rfc5769_vector3() {
2967 let _log = crate::tests::test_init_log();
2968 let data = vec![
2970 0x01, 0x01, 0x00, 0x48, 0x21, 0x12, 0xa4, 0x42, 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae, 0x80, 0x22, 0x00, 0x0b, 0x74, 0x65, 0x73, 0x74, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x00, 0x20, 0x00, 0x14, 0x00, 0x02, 0xa1, 0x47, 0x01, 0x13, 0xa9, 0xfa, 0xa5, 0xd3, 0xf1, 0x79, 0xbc, 0x25, 0xf4, 0xb5, 0xbe, 0xd2, 0xb9, 0xd9, 0x00, 0x08, 0x00, 0x14, 0xa3, 0x82, 0x95, 0x4e, 0x4b, 0xe6, 0x7b, 0xf1, 0x17, 0x84, 0xc9, 0x7c, 0x82, 0x92, 0xc2, 0x75, 0xbf, 0xe3, 0xed, 0x41, 0x80, 0x28, 0x00, 0x04, 0xc8, 0xfb, 0x0b, 0x4c, ];
2994
2995 let msg = Message::from_bytes(&data).unwrap();
2996 assert!(msg.has_class(MessageClass::Success));
2997 assert!(msg.has_method(BINDING));
2998 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
2999 let mut builder = Message::builder(
3000 MessageType::from_class_method(MessageClass::Success, BINDING),
3001 msg.transaction_id(),
3002 MessageWriteVec::new(),
3003 );
3004
3005 assert!(msg.has_attribute(Software::TYPE));
3007 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3008 assert!(Software::try_from(&raw).is_ok());
3009 let software = Software::try_from(&raw).unwrap();
3010 assert_eq!(software.software(), "test vector");
3011 builder.add_attribute(&software).unwrap();
3012
3013 assert!(msg.has_attribute(XorMappedAddress::TYPE));
3015 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3016 assert!(XorMappedAddress::try_from(&raw).is_ok());
3017 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3018 assert_eq!(
3019 xor_mapped_addres.addr(msg.transaction_id()),
3020 "[2001:db8:1234:5678:11:2233:4455:6677]:32853"
3021 .parse()
3022 .unwrap()
3023 );
3024 builder.add_attribute(&xor_mapped_addres).unwrap();
3025
3026 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3028 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3029 });
3030 assert!(matches!(
3031 msg.validate_integrity(&credentials),
3032 Ok(IntegrityAlgorithm::Sha1)
3033 ));
3034 builder
3035 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3036 .unwrap();
3037
3038 assert!(msg.has_attribute(Fingerprint::TYPE));
3040 builder.add_fingerprint().unwrap();
3041
3042 let mut msg_data = builder.finish();
3044 msg_data[35] = 0x20;
3046 assert_eq!(msg_data[..64], data[..64]);
3047 }
3048
3049 #[test]
3050 fn rfc5769_vector4() {
3051 let _log = crate::tests::test_init_log();
3052 let data = vec![
3054 0x00, 0x01, 0x00, 0x60, 0x21, 0x12, 0xa4, 0x42, 0x78, 0xad, 0x34, 0x33, 0xc6, 0xad, 0x72, 0xc0, 0x29, 0xda, 0x41, 0x2e, 0x00, 0x06, 0x00, 0x12, 0xe3, 0x83, 0x9e, 0xe3, 0x83, 0x88, 0xe3, 0x83, 0xaa, 0xe3, 0x83, 0x83, 0xe3, 0x82, 0xaf, 0xe3, 0x82, 0xb9, 0x00, 0x00, 0x00, 0x15, 0x00, 0x1c, 0x66, 0x2f, 0x2f, 0x34, 0x39, 0x39, 0x6b, 0x39, 0x35, 0x34, 0x64, 0x36, 0x4f, 0x4c, 0x33, 0x34, 0x6f, 0x4c, 0x39, 0x46, 0x53, 0x54, 0x76, 0x79, 0x36, 0x34, 0x73, 0x41, 0x00, 0x14, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x08, 0x00, 0x14, 0xf6, 0x70, 0x24, 0x65, 0x6d, 0xd6, 0x4a, 0x3e, 0x02, 0xb8, 0xe0, 0x71, 0x2e, 0x85, 0xc9, 0xa2, 0x8c, 0xa8, 0x96, 0x66, ];
3084
3085 let msg = Message::from_bytes(&data).unwrap();
3086 assert!(msg.has_class(MessageClass::Request));
3087 assert!(msg.has_method(BINDING));
3088 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3089 let mut builder = Message::builder(
3090 MessageType::from_class_method(MessageClass::Request, BINDING),
3091 msg.transaction_id(),
3092 MessageWriteVec::new(),
3093 );
3094
3095 let long_term = LongTermCredentials {
3096 username: "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}".to_owned(),
3097 password: "The\u{00AD}M\u{00AA}tr\u{2168}".to_owned(),
3098 realm: "example.org".to_owned(),
3099 };
3100 assert!(msg.has_attribute(Username::TYPE));
3102 let raw = msg.raw_attribute(Username::TYPE).unwrap();
3103 assert!(Username::try_from(&raw).is_ok());
3104 let username = Username::try_from(&raw).unwrap();
3105 assert_eq!(username.username(), &long_term.username);
3106 builder.add_attribute(&username).unwrap();
3107
3108 let expected_nonce = "f//499k954d6OL34oL9FSTvy64sA";
3110 assert!(msg.has_attribute(Nonce::TYPE));
3111 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3112 assert!(Nonce::try_from(&raw).is_ok());
3113 let nonce = Nonce::try_from(&raw).unwrap();
3114 assert_eq!(nonce.nonce(), expected_nonce);
3115 builder.add_attribute(&nonce).unwrap();
3116
3117 assert!(msg.has_attribute(Realm::TYPE));
3119 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3120 assert!(Realm::try_from(&raw).is_ok());
3121 let realm = Realm::try_from(&raw).unwrap();
3122 assert_eq!(realm.realm(), long_term.realm());
3123 builder.add_attribute(&realm).unwrap();
3124
3125 assert_eq!(builder.finish()[4..], data[4..92]);
3133 }
3134
3135 #[test]
3136 fn rfc8489_vector1() {
3137 let _log = crate::tests::test_init_log();
3138 let data = vec![
3141 0x00, 0x01, 0x00, 0x90, 0x21, 0x12, 0xa4, 0x42, 0x78, 0xad, 0x34, 0x33, 0xc6, 0xad, 0x72, 0xc0, 0x29, 0xda, 0x41, 0x2e, 0x00, 0x1e, 0x00, 0x20, 0x4a, 0x3c, 0xf3, 0x8f, 0xef, 0x69, 0x92, 0xbd, 0xa9, 0x52, 0xc6, 0x78, 0x04, 0x17, 0xda, 0x0f, 0x24, 0x81, 0x94, 0x15, 0x56, 0x9e, 0x60, 0xb2, 0x05, 0xc4, 0x6e, 0x41, 0x40, 0x7f, 0x17, 0x04, 0x00, 0x15, 0x00, 0x29, 0x6f, 0x62, 0x4d, 0x61, 0x74, 0x4a, 0x6f, 0x73, 0x32, 0x41, 0x41, 0x41, 0x43, 0x66, 0x2f, 0x2f, 0x34, 0x39, 0x39, 0x6b, 0x39, 0x35, 0x34, 0x64, 0x36, 0x4f, 0x4c, 0x33, 0x34, 0x6f, 0x4c, 0x39, 0x46, 0x53, 0x54, 0x76, 0x79, 0x36, 0x34, 0x73, 0x41, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x1d, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x20, 0xb5, 0xc7, 0xbf, 0x00, 0x5b, 0x6c, 0x52, 0xa2, 0x1c, 0x51, 0xc5, 0xe8, 0x92, 0xf8, 0x19, 0x24, 0x13, 0x62, 0x96, 0xcb, 0x92, 0x7c, 0x43, 0x14, 0x93, 0x09, 0x27, 0x8c, 0xc6, 0x51, 0x8e, 0x65, ];
3183
3184 let msg = Message::from_bytes(&data).unwrap();
3185 assert!(msg.has_class(MessageClass::Request));
3186 assert!(msg.has_method(BINDING));
3187 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3188 let mut builder = Message::builder(
3189 MessageType::from_class_method(MessageClass::Success, BINDING),
3190 msg.transaction_id(),
3191 MessageWriteVec::new(),
3192 );
3193
3194 let long_term = LongTermCredentials {
3195 username: "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}".to_owned(),
3196 password: "The\u{00AD}M\u{00AA}tr\u{2168}".to_owned(),
3197 realm: "example.org".to_owned(),
3198 };
3199 assert!(msg.has_attribute(Userhash::TYPE));
3201 let raw = msg.raw_attribute(Userhash::TYPE).unwrap();
3202 assert!(Userhash::try_from(&raw).is_ok());
3203 let userhash = Userhash::try_from(&raw).unwrap();
3204 builder.add_attribute(&userhash).unwrap();
3205
3206 let expected_nonce = "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA";
3208 assert!(msg.has_attribute(Nonce::TYPE));
3209 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3210 assert!(Nonce::try_from(&raw).is_ok());
3211 let nonce = Nonce::try_from(&raw).unwrap();
3212 assert_eq!(nonce.nonce(), expected_nonce);
3213 builder.add_attribute(&nonce).unwrap();
3214
3215 assert!(msg.has_attribute(Realm::TYPE));
3217 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3218 assert!(Realm::try_from(&raw).is_ok());
3219 let realm = Realm::try_from(&raw).unwrap();
3220 assert_eq!(realm.realm(), long_term.realm);
3221 builder.add_attribute(&realm).unwrap();
3222
3223 assert!(msg.has_attribute(PasswordAlgorithm::TYPE));
3225 let raw = msg.raw_attribute(PasswordAlgorithm::TYPE).unwrap();
3226 assert!(PasswordAlgorithm::try_from(&raw).is_ok());
3227 let algo = PasswordAlgorithm::try_from(&raw).unwrap();
3228 assert_eq!(algo.algorithm(), PasswordAlgorithmValue::SHA256);
3229 builder.add_attribute(&algo).unwrap();
3230
3231 assert_eq!(builder.finish()[4..], data[4..128]);
3239 }
3240}