1use std::convert::TryFrom;
80
81use byteorder::{BigEndian, ByteOrder};
82
83use crate::attribute::*;
84
85use tracing::{debug, warn};
86
87pub const MAGIC_COOKIE: u32 = 0x2112A442;
89
90pub const BINDING: u16 = 0x0001;
93
94#[derive(Debug, thiserror::Error)]
96pub enum StunParseError {
97 #[error("The provided data is not a STUN message")]
99 NotStun,
100 #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
102 Truncated {
103 expected: usize,
105 actual: usize,
107 },
108 #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
110 TooLarge {
111 expected: usize,
113 actual: usize,
115 },
116 #[error("Integrity value does not match")]
118 IntegrityCheckFailed,
119 #[error("Missing attribute {:?}", .0)]
121 MissingAttribute(AttributeType),
122 #[error("An attribute {:?} was encountered after a message integrity attribute", .0)]
124 AttributeAfterIntegrity(AttributeType),
125 #[error("An attribute {:?} was encountered after a fingerprint attribute", .0)]
127 AttributeAfterFingerprint(AttributeType),
128 #[error("Fingerprint does not match")]
130 FingerprintMismatch,
131 #[error("The provided data does not match the message")]
133 DataMismatch,
134 #[error("The attribute contains invalid data")]
136 InvalidAttributeData,
137 #[error("Cannot parse with this attribute")]
139 WrongAttributeImplementation,
140}
141
142#[derive(Debug, thiserror::Error)]
144pub enum StunWriteError {
145 #[error("The attribute already exists in the message")]
147 AttributeExists(AttributeType),
148 #[error("The message already contains a fingerprint attribute")]
150 FingerprintExists,
151 #[error("The message already contains a message intregrity attribute")]
153 MessageIntegrityExists,
154 #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
156 TooLarge {
157 expected: usize,
159 actual: usize,
161 },
162 #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
164 TooSmall {
165 expected: usize,
167 actual: usize,
169 },
170 #[error("Failed to compute integrity")]
172 IntegrityFailed,
173 #[error("Out of range input provided")]
175 OutOfRange {
176 value: usize,
178 min: usize,
180 max: usize,
182 },
183}
184
185#[derive(Debug, Clone, PartialEq, Eq)]
187#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
188pub struct LongTermCredentials {
189 username: String,
190 password: String,
191 realm: String,
192}
193
194impl LongTermCredentials {
195 pub fn new(username: String, password: String, realm: String) -> Self {
211 Self {
212 username,
213 password,
214 realm,
215 }
216 }
217
218 pub fn username(&self) -> &str {
220 &self.username
221 }
222
223 pub fn password(&self) -> &str {
225 &self.password
226 }
227
228 pub fn realm(&self) -> &str {
230 &self.realm
231 }
232}
233
234#[derive(Debug, Clone, PartialEq, Eq)]
236#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
237pub struct ShortTermCredentials {
238 password: String,
239}
240
241impl ShortTermCredentials {
242 pub fn new(password: String) -> Self {
252 Self { password }
253 }
254
255 pub fn password(&self) -> &str {
257 &self.password
258 }
259}
260
261#[derive(Debug, Clone, PartialEq, Eq)]
265#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
266pub enum MessageIntegrityCredentials {
267 ShortTerm(ShortTermCredentials),
269 LongTerm(LongTermCredentials),
271}
272
273impl From<LongTermCredentials> for MessageIntegrityCredentials {
274 fn from(value: LongTermCredentials) -> Self {
275 MessageIntegrityCredentials::LongTerm(value)
276 }
277}
278
279impl From<ShortTermCredentials> for MessageIntegrityCredentials {
280 fn from(value: ShortTermCredentials) -> Self {
281 MessageIntegrityCredentials::ShortTerm(value)
282 }
283}
284
285impl MessageIntegrityCredentials {
286 fn make_hmac_key(&self) -> Vec<u8> {
287 match self {
288 MessageIntegrityCredentials::ShortTerm(short) => short.password.clone().into(),
289 MessageIntegrityCredentials::LongTerm(long) => {
290 use md5::{Digest, Md5};
291 let data = long.username.clone()
292 + ":"
293 + &long.realm.clone()
294 + ":"
295 + &long.password.clone();
296 let mut digest = Md5::new();
297 digest.update(&data);
298 digest.finalize().to_vec()
299 }
300 }
301 }
302}
303
304#[derive(Copy, Clone, Debug, PartialEq, Eq)]
316pub enum MessageClass {
317 Request,
319 Indication,
321 Success,
323 Error,
325}
326
327impl MessageClass {
328 pub fn is_response(self) -> bool {
331 matches!(self, MessageClass::Success | MessageClass::Error)
332 }
333
334 fn to_bits(self) -> u16 {
335 match self {
336 MessageClass::Request => 0x000,
337 MessageClass::Indication => 0x010,
338 MessageClass::Success => 0x100,
339 MessageClass::Error => 0x110,
340 }
341 }
342}
343
344#[derive(Copy, Clone, Debug, PartialEq, Eq)]
346pub struct MessageType(u16);
347
348impl std::fmt::Display for MessageType {
349 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350 write!(
351 f,
352 "MessageType(class: {:?}, method: {} ({:#x}))",
353 self.class(),
354 self.method(),
355 self.method()
356 )
357 }
358}
359
360impl MessageType {
361 pub fn from_class_method(class: MessageClass, method: u16) -> Self {
372 let class_bits = MessageClass::to_bits(class);
373 let method_bits = method & 0xf | (method & 0x70) << 1 | (method & 0xf80) << 2;
374 Self(class_bits | method_bits)
377 }
378
379 pub fn class(self) -> MessageClass {
389 let class = (self.0 & 0x10) >> 4 | (self.0 & 0x100) >> 7;
390 match class {
391 0x0 => MessageClass::Request,
392 0x1 => MessageClass::Indication,
393 0x2 => MessageClass::Success,
394 0x3 => MessageClass::Error,
395 _ => unreachable!(),
396 }
397 }
398
399 pub fn has_class(self, cls: MessageClass) -> bool {
409 self.class() == cls
410 }
411
412 pub fn is_response(self) -> bool {
428 self.class().is_response()
429 }
430
431 pub fn method(self) -> u16 {
441 self.0 & 0xf | (self.0 & 0xe0) >> 1 | (self.0 & 0x3e00) >> 2
442 }
443
444 pub fn has_method(self, method: u16) -> bool {
454 self.method() == method
455 }
456
457 pub fn write_into(&self, dest: &mut [u8]) {
459 BigEndian::write_u16(dest, self.0);
460 }
461
462 pub fn to_bytes(self) -> Vec<u8> {
464 let mut ret = vec![0; 2];
465 BigEndian::write_u16(&mut ret[0..2], self.0);
466 ret
467 }
468
469 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
471 let data = BigEndian::read_u16(data);
472 if data & 0xc000 != 0x0 {
473 return Err(StunParseError::NotStun);
475 }
476 Ok(Self(data))
477 }
478}
479impl TryFrom<&[u8]> for MessageType {
480 type Error = StunParseError;
481
482 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
483 MessageType::from_bytes(value)
484 }
485}
486
487#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
489pub struct TransactionId {
490 id: u128,
491}
492
493impl TransactionId {
494 pub fn generate() -> TransactionId {
496 use rand::{thread_rng, Rng};
497 let mut rng = thread_rng();
498 rng.gen::<u128>().into()
499 }
500}
501
502impl From<u128> for TransactionId {
503 fn from(id: u128) -> Self {
504 Self {
505 id: id & 0xffff_ffff_ffff_ffff_ffff_ffff,
506 }
507 }
508}
509impl From<TransactionId> for u128 {
510 fn from(id: TransactionId) -> Self {
511 id.id
512 }
513}
514impl std::fmt::Display for TransactionId {
515 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
516 write!(f, "{:#x}", self.id)
517 }
518}
519
520#[derive(Debug)]
524pub struct MessageHeader {
525 mtype: MessageType,
526 transaction_id: TransactionId,
527 length: u16,
528}
529
530impl MessageHeader {
531 pub const LENGTH: usize = 20;
533
534 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
547 if data.len() < 20 {
548 return Err(StunParseError::Truncated {
549 expected: 20,
550 actual: data.len(),
551 });
552 }
553 let mtype = MessageType::from_bytes(data)?;
554 let mlength = BigEndian::read_u16(&data[2..]);
555 let tid = BigEndian::read_u128(&data[4..]);
556 let cookie = (tid >> 96) as u32;
557 if cookie != MAGIC_COOKIE {
558 warn!(
559 "malformed cookie constant {:?} != stored data {:?}",
560 MAGIC_COOKIE, cookie
561 );
562 return Err(StunParseError::NotStun);
563 }
564
565 Ok(Self {
566 mtype,
567 transaction_id: tid.into(),
568 length: mlength,
569 })
570 }
571
572 pub fn data_length(&self) -> u16 {
575 self.length
576 }
577
578 pub fn transaction_id(&self) -> TransactionId {
580 self.transaction_id
581 }
582
583 pub fn get_type(&self) -> MessageType {
585 self.mtype
586 }
587}
588
589#[derive(Debug, Clone)]
594pub struct Message<'a> {
595 data: &'a [u8],
596}
597
598impl<'a> std::fmt::Display for Message<'a> {
599 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
600 write!(
601 f,
602 "Message(class: {:?}, method: {} ({:#x}), transaction: {}, attributes: ",
603 self.get_type().class(),
604 self.get_type().method(),
605 self.get_type().method(),
606 self.transaction_id()
607 )?;
608 let iter = self.iter_attributes();
609 write!(f, "[")?;
610 for (i, a) in iter.enumerate() {
611 if i > 0 {
612 write!(f, ", ")?;
613 }
614 write!(f, "{}", a)?;
615 }
616 write!(f, "]")?;
617 write!(f, ")")
618 }
619}
620
621#[derive(Clone, Copy, Debug, PartialEq, Eq)]
623pub enum IntegrityAlgorithm {
624 Sha1,
626 Sha256,
628}
629
630impl<'a> Message<'a> {
631 pub fn builder<'b>(mtype: MessageType, transaction_id: TransactionId) -> MessageBuilder<'b> {
646 MessageBuilder {
647 msg_type: mtype,
648 transaction_id,
649 attributes: Vec::with_capacity(8),
650 attribute_types: smallvec::smallvec![],
651 }
652 }
653
654 pub fn builder_request<'b>(method: u16) -> MessageBuilder<'b> {
667 Message::builder(
668 MessageType::from_class_method(MessageClass::Request, method),
669 TransactionId::generate(),
670 )
671 }
672
673 pub fn builder_success<'b>(orig: &Message) -> MessageBuilder<'b> {
692 if !orig.has_class(MessageClass::Request) {
693 panic!(
694 "A success response message was attempted to be created from a non-request message"
695 );
696 }
697 Message::builder(
698 MessageType::from_class_method(MessageClass::Success, orig.method()),
699 orig.transaction_id(),
700 )
701 }
702
703 pub fn builder_error(orig: &Message) -> MessageBuilder<'a> {
722 if !orig.has_class(MessageClass::Request) {
723 panic!(
724 "An error response message was attempted to be created from a non-request message"
725 );
726 }
727 Message::builder(
728 MessageType::from_class_method(MessageClass::Error, orig.method()),
729 orig.transaction_id(),
730 )
731 }
732
733 pub fn get_type(&self) -> MessageType {
746 MessageType::try_from(&self.data[..2]).unwrap()
747 }
748
749 pub fn class(&self) -> MessageClass {
760 self.get_type().class()
761 }
762
763 pub fn has_class(&self, cls: MessageClass) -> bool {
774 self.class() == cls
775 }
776
777 pub fn is_response(&self) -> bool {
798 self.class().is_response()
799 }
800
801 pub fn method(&self) -> u16 {
812 self.get_type().method()
813 }
814
815 pub fn has_method(&self, method: u16) -> bool {
827 self.method() == method
828 }
829
830 pub fn transaction_id(&self) -> TransactionId {
843 BigEndian::read_u128(&self.data[4..]).into()
844 }
845
846 #[tracing::instrument(
862 name = "message_from_bytes",
863 level = "trace",
864 skip(data),
865 fields(
866 data.len = data.len()
867 )
868 )]
869 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
870 let orig_data = data;
871
872 let header = MessageHeader::from_bytes(data)?;
873 let mlength = header.data_length() as usize;
874 if mlength + MessageHeader::LENGTH > data.len() {
875 warn!(
877 "malformed advertised size {:?} and data size {:?} don't match",
878 mlength + 20,
879 data.len()
880 );
881 return Err(StunParseError::Truncated {
882 expected: mlength + MessageHeader::LENGTH,
883 actual: data.len(),
884 });
885 }
886
887 let mut data_offset = MessageHeader::LENGTH;
888 let mut data = &data[MessageHeader::LENGTH..];
889 let ending_attributes = [
890 MessageIntegrity::TYPE,
891 MessageIntegritySha256::TYPE,
892 Fingerprint::TYPE,
893 ];
894 let mut seen_ending_attributes = [AttributeType::new(0); 3];
896 let mut seen_ending_len = 0;
897 while !data.is_empty() {
898 let attr = RawAttribute::from_bytes(data).map_err(|e| {
899 warn!(
900 "failed to parse message attribute at offset {data_offset}: {:?}",
901 e
902 );
903 match e {
904 StunParseError::Truncated { expected, actual } => StunParseError::Truncated {
905 expected: expected + 4 + data_offset,
906 actual: actual + 4 + data_offset,
907 },
908 StunParseError::TooLarge { expected, actual } => StunParseError::TooLarge {
909 expected: expected + 4 + data_offset,
910 actual: actual + 4 + data_offset,
911 },
912 e => e,
913 }
914 })?;
915
916 if seen_ending_len > 0 && !ending_attributes.contains(&attr.get_type()) {
919 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
920 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
921 return Err(StunParseError::AttributeAfterFingerprint(attr.get_type()));
922 } else {
923 warn!(
925 "unexpected attribute {} after MESSAGE_INTEGRITY",
926 attr.get_type()
927 );
928 return Err(StunParseError::AttributeAfterIntegrity(attr.get_type()));
929 }
930 }
931
932 if ending_attributes.contains(&attr.get_type()) {
933 if seen_ending_attributes.contains(&attr.get_type()) {
934 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
935 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
936 return Err(StunParseError::AttributeAfterFingerprint(attr.get_type()));
937 } else {
938 warn!(
940 "unexpected attribute {} after MESSAGE_INTEGRITY",
941 attr.get_type()
942 );
943 return Err(StunParseError::AttributeAfterIntegrity(attr.get_type()));
944 }
945 } else {
946 seen_ending_attributes[seen_ending_len] = attr.get_type();
947 seen_ending_len += 1;
948 }
950 }
951 let padded_len = attr.padded_len();
952 if padded_len > data.len() {
953 warn!(
954 "attribute {:?} extends past the end of the data",
955 attr.get_type()
956 );
957 return Err(StunParseError::Truncated {
958 expected: data_offset + padded_len,
959 actual: data_offset + data.len(),
960 });
961 }
962 if attr.get_type() == Fingerprint::TYPE {
963 let f = Fingerprint::from_raw(&attr)?;
964 let msg_fingerprint = f.fingerprint();
965 let mut fingerprint_data = orig_data[..data_offset].to_vec();
966 BigEndian::write_u16(
967 &mut fingerprint_data[2..4],
968 (data_offset + padded_len - MessageHeader::LENGTH) as u16,
969 );
970 let calculated_fingerprint = Fingerprint::compute(&fingerprint_data);
971 if &calculated_fingerprint != msg_fingerprint {
972 warn!(
973 "fingerprint mismatch {:?} != {:?}",
974 calculated_fingerprint, msg_fingerprint
975 );
976 return Err(StunParseError::FingerprintMismatch);
977 }
978 }
979 data = &data[padded_len..];
980 data_offset += padded_len;
981 }
982 Ok(Message { data: orig_data })
983 }
984
985 #[tracing::instrument(
1007 name = "message_validate_integrity",
1008 level = "trace",
1009 skip(self, credentials),
1010 fields(
1011 msg.transaction = %self.transaction_id(),
1012 )
1013 )]
1014 pub fn validate_integrity(
1015 &self,
1016 credentials: &MessageIntegrityCredentials,
1017 ) -> Result<IntegrityAlgorithm, StunParseError> {
1018 debug!("using credentials {credentials:?}");
1019 let raw_sha1 = self.raw_attribute(MessageIntegrity::TYPE);
1020 let raw_sha256 = self.raw_attribute(MessageIntegritySha256::TYPE);
1021 let (algo, msg_hmac) = match (raw_sha1, raw_sha256) {
1022 (_, Some(sha256)) => {
1023 let integrity = MessageIntegritySha256::try_from(&sha256)?;
1024 (IntegrityAlgorithm::Sha256, integrity.hmac().to_vec())
1025 }
1026 (Some(sha1), None) => {
1027 let integrity = MessageIntegrity::try_from(&sha1)?;
1028 (IntegrityAlgorithm::Sha1, integrity.hmac().to_vec())
1029 }
1030 (None, None) => return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE)),
1031 };
1032
1033 let data = self.data;
1036 debug_assert!(data.len() >= MessageHeader::LENGTH);
1037 let mut data = &data[MessageHeader::LENGTH..];
1038 let mut data_offset = MessageHeader::LENGTH;
1039 while !data.is_empty() {
1040 let attr = RawAttribute::from_bytes(data)?;
1041 if algo == IntegrityAlgorithm::Sha1 && attr.get_type() == MessageIntegrity::TYPE {
1042 let msg = MessageIntegrity::try_from(&attr)?;
1043 debug_assert!(msg.hmac().as_slice() == msg_hmac);
1044
1045 let key = credentials.make_hmac_key();
1048 let mut hmac_data = self.data[..data_offset].to_vec();
1049 BigEndian::write_u16(
1050 &mut hmac_data[2..4],
1051 data_offset as u16 + 24 - MessageHeader::LENGTH as u16,
1052 );
1053 MessageIntegrity::verify(
1054 &hmac_data,
1055 &key,
1056 msg_hmac.as_slice().try_into().unwrap(),
1057 )?;
1058 return Ok(algo);
1059 } else if algo == IntegrityAlgorithm::Sha256
1060 && attr.get_type() == MessageIntegritySha256::TYPE
1061 {
1062 let msg = MessageIntegritySha256::try_from(&attr)?;
1063 debug_assert!(msg.hmac() == msg_hmac);
1064
1065 let key = credentials.make_hmac_key();
1068 let mut hmac_data = self.data[..data_offset].to_vec();
1069 BigEndian::write_u16(
1070 &mut hmac_data[2..4],
1071 data_offset as u16 + attr.length() + 4 - MessageHeader::LENGTH as u16,
1072 );
1073 MessageIntegritySha256::verify(&hmac_data, &key, &msg_hmac)?;
1074 return Ok(algo);
1075 }
1076 let padded_len = attr.padded_len();
1077 debug_assert!(padded_len <= data.len());
1079 data = &data[padded_len..];
1080 data_offset += padded_len;
1081 }
1082
1083 unreachable!();
1086 }
1087
1088 #[tracing::instrument(
1105 name = "message_get_raw_attribute",
1106 level = "trace",
1107 ret,
1108 skip(self, atype),
1109 fields(
1110 msg.transaction = %self.transaction_id(),
1111 attribute_type = %atype,
1112 )
1113 )]
1114 pub fn raw_attribute(&self, atype: AttributeType) -> Option<RawAttribute> {
1115 self.iter_attributes().find(|attr| attr.get_type() == atype)
1116 }
1117
1118 #[tracing::instrument(
1139 name = "message_get_attribute",
1140 level = "trace",
1141 ret,
1142 skip(self),
1143 fields(
1144 msg.transaction = %self.transaction_id(),
1145 attribute_type = %A::TYPE,
1146 )
1147 )]
1148 pub fn attribute<A: AttributeFromRaw<StunParseError> + AttributeStaticType>(
1149 &self,
1150 ) -> Result<A, StunParseError> {
1151 self.iter_attributes()
1152 .find(|attr| attr.get_type() == A::TYPE)
1153 .ok_or(StunParseError::MissingAttribute(A::TYPE))
1154 .and_then(|raw| A::from_raw(&raw))
1155 }
1156
1157 pub fn iter_attributes(&self) -> impl Iterator<Item = RawAttribute> {
1159 MessageAttributesIter {
1160 data: self.data,
1161 data_i: MessageHeader::LENGTH,
1162 seen_message_integrity: false,
1163 }
1164 }
1165
1166 #[tracing::instrument(
1211 level = "trace",
1212 skip(msg),
1213 fields(
1214 msg.transaction = %msg.transaction_id(),
1215 )
1216 )]
1217 pub fn check_attribute_types<'b>(
1218 msg: &Message,
1219 supported: &[AttributeType],
1220 required_in_msg: &[AttributeType],
1221 ) -> Option<MessageBuilder<'b>> {
1222 let unsupported: Vec<AttributeType> = msg
1224 .iter_attributes()
1225 .map(|a| a.get_type())
1226 .filter(|&at| at.comprehension_required() && !supported.iter().any(|&a| a == at))
1228 .collect();
1229 if !unsupported.is_empty() {
1230 warn!(
1231 "Message contains unknown comprehension required attributes {:?}, returning unknown attributes",
1232 unsupported
1233 );
1234 return Some(Message::unknown_attributes(msg, &unsupported));
1235 }
1236 let has_required_attribute_missing = required_in_msg
1237 .iter()
1238 .any(|&at| !msg.iter_attributes().map(|a| a.get_type()).any(|a| a == at));
1240 if has_required_attribute_missing {
1241 warn!("Message is missing required attributes, returning bad request");
1242 return Some(Message::bad_request(msg));
1243 }
1244 None
1245 }
1246
1247 pub fn unknown_attributes<'b>(
1268 src: &Message,
1269 attributes: &[AttributeType],
1270 ) -> MessageBuilder<'b> {
1271 let mut out = Message::builder_error(src);
1272 let software = Software::new("stun-types").unwrap();
1273 out.add_attribute(&software).unwrap();
1274 let error = ErrorCode::new(420, "Unknown Attributes").unwrap();
1275 out.add_attribute(&error).unwrap();
1276 let unknown = UnknownAttributes::new(attributes);
1277 if !attributes.is_empty() {
1278 out.add_attribute(&unknown).unwrap();
1279 }
1280 out.into_owned()
1281 }
1282
1283 pub fn bad_request<'b>(src: &'a Message) -> MessageBuilder<'b> {
1300 let mut out = Message::builder_error(src);
1301 let software = Software::new("stun-types").unwrap();
1302 out.add_attribute(&software).unwrap();
1303 let error = ErrorCode::new(400, "Bad Request").unwrap();
1304 out.add_attribute(&error).unwrap();
1305 out.into_owned()
1306 }
1307
1308 pub fn has_attribute(&self, atype: AttributeType) -> bool {
1323 self.iter_attributes().any(|attr| attr.get_type() == atype)
1324 }
1325}
1326impl<'a> TryFrom<&'a [u8]> for Message<'a> {
1327 type Error = StunParseError;
1328
1329 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
1330 Message::from_bytes(value)
1331 }
1332}
1333
1334#[doc(hidden)]
1335#[derive(Debug)]
1336pub struct MessageAttributesIter<'a> {
1337 data: &'a [u8],
1338 data_i: usize,
1339 seen_message_integrity: bool,
1340}
1341
1342impl<'a> Iterator for MessageAttributesIter<'a> {
1343 type Item = RawAttribute<'a>;
1344
1345 fn next(&mut self) -> Option<Self::Item> {
1346 if self.data_i >= self.data.len() {
1347 return None;
1348 }
1349
1350 let Ok(attr) = RawAttribute::from_bytes(&self.data[self.data_i..]) else {
1351 self.data_i = self.data.len();
1352 return None;
1353 };
1354 let padded_len = attr.padded_len();
1355 self.data_i += padded_len;
1356 if self.seen_message_integrity {
1357 if attr.get_type() == Fingerprint::TYPE {
1358 return Some(attr);
1359 }
1360 return None;
1361 }
1362 if attr.get_type() == MessageIntegrity::TYPE
1363 || attr.get_type() == MessageIntegritySha256::TYPE
1364 {
1365 self.seen_message_integrity = true;
1366 }
1367
1368 Some(attr)
1369 }
1370}
1371
1372#[derive(Clone, Debug)]
1373enum AttrOrRaw<'a> {
1374 Attr(&'a dyn AttributeWrite),
1375 Raw(RawAttribute<'a>),
1376}
1377
1378impl<'a> AttrOrRaw<'a> {
1379 fn into_owned<'b>(self) -> AttrOrRaw<'b> {
1380 match self {
1381 AttrOrRaw::Raw(raw) => AttrOrRaw::Raw(raw.into_owned()),
1382 AttrOrRaw::Attr(attr) => AttrOrRaw::Raw(attr.to_raw().into_owned()),
1383 }
1384 }
1385
1386 fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
1387 match self {
1388 AttrOrRaw::Raw(raw) => raw.write_into(dest),
1389 AttrOrRaw::Attr(attr) => attr.write_into(dest),
1390 }
1391 }
1392}
1393
1394impl<'a> Attribute for AttrOrRaw<'a> {
1395 fn length(&self) -> u16 {
1396 match self {
1397 Self::Attr(attr) => attr.length(),
1398 Self::Raw(raw) => raw.length(),
1399 }
1400 }
1401
1402 fn get_type(&self) -> AttributeType {
1403 match self {
1404 Self::Attr(attr) => attr.get_type(),
1405 Self::Raw(raw) => raw.get_type(),
1406 }
1407 }
1408}
1409
1410#[derive(Clone, Debug)]
1412pub struct MessageBuilder<'a> {
1413 msg_type: MessageType,
1414 transaction_id: TransactionId,
1415 attributes: Vec<AttrOrRaw<'a>>,
1416 attribute_types: smallvec::SmallVec<[AttributeType; 16]>,
1417}
1418
1419impl<'a> MessageBuilder<'a> {
1420 pub fn into_owned<'b>(self) -> MessageBuilder<'b> {
1422 MessageBuilder {
1423 msg_type: self.msg_type,
1424 transaction_id: self.transaction_id,
1425 attributes: self
1426 .attributes
1427 .into_iter()
1428 .map(|attr| attr.into_owned())
1429 .collect(),
1430 attribute_types: self.attribute_types.clone(),
1431 }
1432 }
1433
1434 pub fn transaction_id(&self) -> TransactionId {
1447 self.transaction_id
1448 }
1449
1450 pub fn has_class(&self, cls: MessageClass) -> bool {
1452 self.msg_type.class() == cls
1453 }
1454
1455 #[tracing::instrument(
1468 name = "message_build",
1469 level = "trace",
1470 skip(self),
1471 fields(
1472 msg.transaction_id = %self.transaction_id()
1473 )
1474 )]
1475 pub fn build(&self) -> Vec<u8> {
1476 let attr_size = self
1477 .attributes
1478 .iter()
1479 .map(|attr| attr.padded_len())
1480 .sum::<usize>();
1481 let mut ret = vec![0; MessageHeader::LENGTH + attr_size];
1482 let _ = self.write_into(&mut ret);
1483 ret
1484 }
1485
1486 #[tracing::instrument(
1489 name = "message_build",
1490 level = "trace",
1491 skip(self),
1492 fields(
1493 msg.transaction_id = %self.transaction_id()
1494 )
1495 )]
1496 pub fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
1497 let len = self.byte_len();
1498 if len > dest.len() {
1499 return Err(StunWriteError::TooSmall {
1500 expected: len,
1501 actual: dest.len(),
1502 });
1503 }
1504 self.msg_type.write_into(&mut dest[..2]);
1505 let transaction: u128 = self.transaction_id.into();
1506 let tid = (MAGIC_COOKIE as u128) << 96 | transaction & 0xffff_ffff_ffff_ffff_ffff_ffff;
1507 BigEndian::write_u128(&mut dest[4..20], tid);
1508 BigEndian::write_u16(&mut dest[2..4], (len - MessageHeader::LENGTH) as u16);
1509 let mut offset = MessageHeader::LENGTH;
1510 for attr in &self.attributes {
1511 offset += attr.write_into(&mut dest[offset..])?;
1512 }
1513 Ok(offset)
1514 }
1515
1516 pub fn byte_len(&self) -> usize {
1519 MessageHeader::LENGTH
1520 + self
1521 .attributes
1522 .iter()
1523 .map(|attr| attr.padded_len())
1524 .sum::<usize>()
1525 }
1526
1527 fn integrity_bytes_from_message(&self, extra_len: u16) -> Vec<u8> {
1530 let mut bytes = self.build();
1531 let existing_len = BigEndian::read_u16(&bytes[2..4]);
1533 BigEndian::write_u16(&mut bytes[2..4], existing_len + extra_len);
1534 bytes
1535 }
1536
1537 #[tracing::instrument(
1571 name = "message_add_integrity",
1572 level = "trace",
1573 err,
1574 skip(self),
1575 fields(
1576 msg.transaction = %self.transaction_id(),
1577 )
1578 )]
1579 pub fn add_message_integrity(
1580 &mut self,
1581 credentials: &MessageIntegrityCredentials,
1582 algorithm: IntegrityAlgorithm,
1583 ) -> Result<(), StunWriteError> {
1584 let mut atypes = [AttributeType::new(0); 3];
1585 let mut i = 0;
1586 atypes[i] = match algorithm {
1587 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
1588 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
1589 };
1590 i += 1;
1591 if algorithm == IntegrityAlgorithm::Sha1 {
1592 atypes[i] = MessageIntegritySha256::TYPE;
1593 i += 1;
1594 }
1595 atypes[i] = Fingerprint::TYPE;
1596 i += 1;
1597
1598 match self.has_any_attribute(&atypes[..i]) {
1599 Some(MessageIntegrity::TYPE) => {
1601 return Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
1602 }
1603 Some(MessageIntegritySha256::TYPE) => {
1604 return Err(StunWriteError::AttributeExists(
1605 MessageIntegritySha256::TYPE,
1606 ));
1607 }
1608 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
1609 _ => (),
1610 }
1611
1612 self.add_message_integrity_unchecked(credentials, algorithm);
1613
1614 Ok(())
1615 }
1616
1617 fn add_message_integrity_unchecked(
1618 &mut self,
1619 credentials: &MessageIntegrityCredentials,
1620 algorithm: IntegrityAlgorithm,
1621 ) {
1622 let key = credentials.make_hmac_key();
1623 match algorithm {
1624 IntegrityAlgorithm::Sha1 => {
1625 let bytes = self.integrity_bytes_from_message(24);
1626 let integrity = MessageIntegrity::compute(&bytes, &key).unwrap();
1627 self.attributes.push(
1628 AttrOrRaw::Raw(RawAttribute::from(&MessageIntegrity::new(integrity)))
1629 .into_owned(),
1630 );
1631 self.attribute_types.push(MessageIntegrity::TYPE);
1632 }
1633 IntegrityAlgorithm::Sha256 => {
1634 let bytes = self.integrity_bytes_from_message(36);
1635 let integrity = MessageIntegritySha256::compute(&bytes, &key).unwrap();
1636 self.attributes.push(AttrOrRaw::Raw(
1637 RawAttribute::from(&MessageIntegritySha256::new(integrity.as_slice()).unwrap())
1638 .into_owned(),
1639 ));
1640 self.attribute_types.push(MessageIntegritySha256::TYPE);
1641 }
1642 }
1643 }
1644
1645 #[tracing::instrument(
1662 name = "message_add_fingerprint",
1663 level = "trace",
1664 skip(self),
1665 fields(
1666 msg.transaction = %self.transaction_id(),
1667 )
1668 )]
1669 pub fn add_fingerprint(&mut self) -> Result<(), StunWriteError> {
1670 if self.has_attribute(Fingerprint::TYPE) {
1671 return Err(StunWriteError::AttributeExists(Fingerprint::TYPE));
1672 }
1673
1674 self.add_fingerprint_unchecked();
1675
1676 Ok(())
1677 }
1678
1679 fn add_fingerprint_unchecked(&mut self) {
1680 let mut bytes = self.build();
1683 let existing_len = BigEndian::read_u16(&bytes[2..4]);
1685 BigEndian::write_u16(&mut bytes[2..4], existing_len + 8);
1686 let fingerprint = Fingerprint::compute(&bytes);
1687 self.attributes
1688 .push(AttrOrRaw::Attr(&Fingerprint::new(fingerprint)).into_owned());
1689 self.attribute_types.push(Fingerprint::TYPE);
1690 }
1691
1692 #[tracing::instrument(
1721 name = "message_add_attribute",
1722 level = "trace",
1723 err,
1724 skip(self, attr),
1725 fields(
1726 msg.transaction = %self.transaction_id(),
1727 )
1728 )]
1729 pub fn add_attribute(&mut self, attr: &'a dyn AttributeWrite) -> Result<(), StunWriteError> {
1730 let ty = attr.get_type();
1731 match ty {
1733 MessageIntegrity::TYPE => {
1734 panic!("Cannot write MessageIntegrity with `add_attribute`. Use add_message_integrity() instead");
1735 }
1736 MessageIntegritySha256::TYPE => {
1737 panic!("Cannot write MessageIntegritySha256 with `add_attribute`. Use add_message_integrity() instead");
1738 }
1739 Fingerprint::TYPE => {
1740 panic!(
1741 "Cannot write Fingerprint with `add_attribute`. Use add_fingerprint() instead"
1742 );
1743 }
1744 _ => (),
1745 }
1746 match self.has_any_attribute(&[
1747 ty,
1748 MessageIntegrity::TYPE,
1749 MessageIntegritySha256::TYPE,
1750 Fingerprint::TYPE,
1751 ]) {
1752 Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
1754 Some(MessageIntegritySha256::TYPE) => {
1755 return Err(StunWriteError::MessageIntegrityExists)
1756 }
1757 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
1758 Some(typ) if typ == ty => return Err(StunWriteError::AttributeExists(ty)),
1759 _ => (),
1760 }
1761 self.attributes.push(AttrOrRaw::Attr(attr));
1762 self.attribute_types.push(ty);
1763 Ok(())
1764 }
1765
1766 #[tracing::instrument(
1782 name = "message_add_raw_attribute",
1783 level = "trace",
1784 err,
1785 skip(self, attr),
1786 fields(
1787 msg.transaction = %self.transaction_id(),
1788 )
1789 )]
1790 pub fn add_raw_attribute(&mut self, attr: RawAttribute<'a>) -> Result<(), StunWriteError> {
1791 let ty = attr.get_type();
1792 match ty {
1794 MessageIntegrity::TYPE => {
1795 panic!("Cannot write MessageIntegrity with `add_raw_attribute`. Use add_message_integrity() instead");
1796 }
1797 MessageIntegritySha256::TYPE => {
1798 panic!("Cannot write MessageIntegritySha256 with `add_raw_attribute`. Use add_message_integrity() instead");
1799 }
1800 Fingerprint::TYPE => {
1801 panic!("Cannot write Fingerprint with `add_raw_attribute`. Use add_fingerprint() instead");
1802 }
1803 _ => (),
1804 }
1805 match self.has_any_attribute(&[
1806 ty,
1807 MessageIntegrity::TYPE,
1808 MessageIntegritySha256::TYPE,
1809 Fingerprint::TYPE,
1810 ]) {
1811 Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
1813 Some(MessageIntegritySha256::TYPE) => {
1814 return Err(StunWriteError::MessageIntegrityExists)
1815 }
1816 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
1817 Some(typ) if typ == ty => return Err(StunWriteError::AttributeExists(ty)),
1818 _ => (),
1819 }
1820 self.attributes.push(AttrOrRaw::Raw(attr));
1821 self.attribute_types.push(ty);
1822 Ok(())
1823 }
1824
1825 pub fn has_attribute(&self, atype: AttributeType) -> bool {
1827 self.attribute_types.iter().any(|&ty| ty == atype)
1828 }
1829
1830 pub fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
1833 self.attribute_types
1834 .iter()
1835 .find(|&ty| atypes.contains(ty))
1836 .cloned()
1837 }
1838}
1839
1840#[cfg(test)]
1841mod tests {
1842 use super::*;
1843
1844 #[test]
1845 fn msg_type_roundtrip() {
1846 let _log = crate::tests::test_init_log();
1847 for m in 0..0xfff {
1849 let classes = vec![
1850 MessageClass::Request,
1851 MessageClass::Indication,
1852 MessageClass::Success,
1853 MessageClass::Error,
1854 ];
1855 for c in classes {
1856 let mtype = MessageType::from_class_method(c, m);
1857 assert_eq!(mtype.class(), c);
1858 assert_eq!(mtype.method(), m);
1859 let bytes = mtype.to_bytes();
1860 let ptype = MessageType::from_bytes(&bytes).unwrap();
1861 assert_eq!(mtype, ptype);
1862 }
1863 }
1864 }
1865
1866 #[test]
1867 fn msg_type_not_stun() {
1868 assert!(matches!(
1869 MessageType::from_bytes(&[0xc0, 0x00]),
1870 Err(StunParseError::NotStun)
1871 ));
1872 }
1873
1874 #[test]
1875 fn msg_roundtrip() {
1876 let _log = crate::tests::test_init_log();
1877 for m in (0x009..0x4ff).step_by(0x123) {
1879 let classes = vec![
1880 MessageClass::Request,
1881 MessageClass::Indication,
1882 MessageClass::Success,
1883 MessageClass::Error,
1884 ];
1885 for c in classes {
1886 let mtype = MessageType::from_class_method(c, m);
1887 for tid in (0x18..0xff_ffff_ffff_ffff_ffff).step_by(0xfedc_ba98_7654_3210) {
1888 let mut msg = Message::builder(mtype, tid.into());
1889 let attr = RawAttribute::new(1.into(), &[3]);
1890 assert!(msg.add_raw_attribute(attr.clone()).is_ok());
1891 let data = msg.build();
1892
1893 let msg = Message::from_bytes(&data).unwrap();
1894 let msg_attr = msg.raw_attribute(1.into()).unwrap();
1895 assert_eq!(msg_attr, attr);
1896 assert_eq!(msg.get_type(), mtype);
1897 assert_eq!(msg.transaction_id(), tid.into());
1898 }
1899 }
1900 }
1901 }
1902
1903 #[test]
1904 fn unknown_attributes() {
1905 let _log = crate::tests::test_init_log();
1906 let src = Message::builder_request(BINDING).build();
1907 let src = Message::from_bytes(&src).unwrap();
1908 let msg = Message::unknown_attributes(&src, &[Software::TYPE]).build();
1909 let msg = Message::from_bytes(&msg).unwrap();
1910 assert_eq!(msg.transaction_id(), src.transaction_id());
1911 assert_eq!(msg.class(), MessageClass::Error);
1912 assert_eq!(msg.method(), src.method());
1913 let err = msg.attribute::<ErrorCode>().unwrap();
1914 assert_eq!(err.code(), 420);
1915 let unknown_attrs = msg.attribute::<UnknownAttributes>().unwrap();
1916 assert!(unknown_attrs.has_attribute(Software::TYPE));
1917 }
1918
1919 #[test]
1920 fn bad_request() {
1921 let _log = crate::tests::test_init_log();
1922 let src = Message::builder_request(BINDING).build();
1923 let src = Message::from_bytes(&src).unwrap();
1924 let msg = Message::bad_request(&src).build();
1925 let msg = Message::from_bytes(&msg).unwrap();
1926 assert_eq!(msg.transaction_id(), src.transaction_id());
1927 assert_eq!(msg.class(), MessageClass::Error);
1928 assert_eq!(msg.method(), src.method());
1929 let err = msg.attribute::<ErrorCode>().unwrap();
1930 assert_eq!(err.code(), 400);
1931 }
1932
1933 #[test]
1934 fn fingerprint() {
1935 let _log = crate::tests::test_init_log();
1936 let mut msg = Message::builder_request(BINDING);
1937 let software = Software::new("s").unwrap();
1938 msg.add_attribute(&software).unwrap();
1939 msg.add_fingerprint().unwrap();
1940 let bytes = msg.build();
1941 let new_msg = Message::from_bytes(&bytes).unwrap();
1943 let software = new_msg.attribute::<Software>().unwrap();
1944 assert_eq!(software.software(), "s");
1945 let _new_fingerprint = new_msg.attribute::<Fingerprint>().unwrap();
1946 }
1947
1948 #[test]
1949 fn integrity() {
1950 let _log = crate::tests::test_init_log();
1951 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
1952 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
1953 let mut msg = Message::builder_request(BINDING);
1954 let software = Software::new("s").unwrap();
1955 msg.add_attribute(&software).unwrap();
1956 msg.add_message_integrity(&credentials, algorithm).unwrap();
1957 let bytes = msg.build();
1958 let new_msg = Message::from_bytes(&bytes).unwrap();
1960 new_msg.validate_integrity(&credentials).unwrap();
1961 let software = new_msg.attribute::<Software>().unwrap();
1962 assert_eq!(software.software(), "s");
1963 }
1964 }
1965
1966 #[test]
1967 fn write_into_short_destination() {
1968 let _log = crate::tests::test_init_log();
1969 let mut msg = Message::builder_request(BINDING);
1970 let software = Software::new("s").unwrap();
1971 msg.add_attribute(&software).unwrap();
1972 let len = msg.byte_len();
1973 let mut dest = vec![0; len - 1];
1974 assert!(
1975 matches!(msg.write_into(&mut dest), Err(StunWriteError::TooSmall {
1976 expected,
1977 actual,
1978 }) if expected == len && actual == len - 1)
1979 );
1980 }
1981
1982 #[test]
1983 fn add_duplicate_integrity() {
1984 let _log = crate::tests::test_init_log();
1985 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
1986 let mut msg = Message::builder_request(BINDING);
1987 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
1988 .unwrap();
1989 assert!(matches!(
1990 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
1991 Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
1992 ));
1993 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
1994 .unwrap();
1995 assert!(matches!(
1996 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256),
1997 Err(StunWriteError::AttributeExists(
1998 MessageIntegritySha256::TYPE
1999 ))
2000 ));
2001 let software = Software::new("s").unwrap();
2002 assert!(matches!(
2003 msg.add_attribute(&software),
2004 Err(StunWriteError::MessageIntegrityExists)
2005 ));
2006 }
2007
2008 #[test]
2009 fn add_sha1_integrity_after_sha256() {
2010 let _log = crate::tests::test_init_log();
2011 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2012 let mut msg = Message::builder_request(BINDING);
2013 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2014 .unwrap();
2015 assert!(matches!(
2016 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2017 Err(StunWriteError::AttributeExists(
2018 MessageIntegritySha256::TYPE
2019 ))
2020 ));
2021 }
2022
2023 #[test]
2024 fn add_attribute_after_integrity() {
2025 let _log = crate::tests::test_init_log();
2026 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2027 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2028 let mut msg = Message::builder_request(BINDING);
2029 msg.add_message_integrity(&credentials, algorithm).unwrap();
2030 let software = Software::new("s").unwrap();
2031 assert!(matches!(
2032 msg.add_attribute(&software),
2033 Err(StunWriteError::MessageIntegrityExists)
2034 ));
2035 }
2036 }
2037
2038 #[test]
2039 fn add_raw_attribute_after_integrity() {
2040 let _log = crate::tests::test_init_log();
2041 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2042 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2043 let mut msg = Message::builder_request(BINDING);
2044 msg.add_message_integrity(&credentials, algorithm).unwrap();
2045 let software = Software::new("s").unwrap();
2046 let raw = software.to_raw();
2047 assert!(matches!(
2048 msg.add_raw_attribute(raw),
2049 Err(StunWriteError::MessageIntegrityExists)
2050 ));
2051 }
2052 }
2053
2054 #[test]
2055 fn add_integrity_after_fingerprint() {
2056 let _log = crate::tests::test_init_log();
2057 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2058 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2059 let mut msg = Message::builder_request(BINDING);
2060 msg.add_fingerprint().unwrap();
2061 assert!(matches!(
2062 msg.add_message_integrity(&credentials, algorithm),
2063 Err(StunWriteError::FingerprintExists)
2064 ));
2065 }
2066 }
2067
2068 #[test]
2069 fn duplicate_add_attribute() {
2070 let _log = crate::tests::test_init_log();
2071 let mut msg = Message::builder_request(BINDING);
2072 let software = Software::new("s").unwrap();
2073 msg.add_attribute(&software).unwrap();
2074 assert!(matches!(
2075 msg.add_attribute(&software),
2076 Err(StunWriteError::AttributeExists(ty)) if ty == Software::TYPE
2077 ));
2078 }
2079
2080 #[test]
2081 fn duplicate_add_raw_attribute() {
2082 let _log = crate::tests::test_init_log();
2083 let mut msg = Message::builder_request(BINDING);
2084 let software = Software::new("s").unwrap();
2085 let raw = software.to_raw();
2086 msg.add_raw_attribute(raw.clone()).unwrap();
2087 assert!(matches!(
2088 msg.add_raw_attribute(raw),
2089 Err(StunWriteError::AttributeExists(ty)) if ty == Software::TYPE
2090 ));
2091 }
2092
2093 #[test]
2094 fn duplicate_fingerprint() {
2095 let _log = crate::tests::test_init_log();
2096 let mut msg = Message::builder_request(BINDING);
2097 msg.add_fingerprint().unwrap();
2098 assert!(matches!(
2099 msg.add_fingerprint(),
2100 Err(StunWriteError::AttributeExists(Fingerprint::TYPE))
2101 ));
2102 }
2103
2104 #[test]
2105 fn parse_invalid_fingerprint() {
2106 let _log = crate::tests::test_init_log();
2107 let mut msg = Message::builder_request(BINDING);
2108 msg.add_fingerprint().unwrap();
2109 let mut bytes = msg.build();
2110 bytes[24] = 0x80;
2111 bytes[25] = 0x80;
2112 bytes[26] = 0x80;
2113 bytes[27] = 0x80;
2114 assert!(matches!(
2115 Message::from_bytes(&bytes),
2116 Err(StunParseError::FingerprintMismatch)
2117 ));
2118 }
2119
2120 #[test]
2121 fn parse_wrong_magic() {
2122 let _log = crate::tests::test_init_log();
2123 let mut msg = Message::builder_request(BINDING);
2124 msg.add_fingerprint().unwrap();
2125 let mut bytes = msg.build();
2126 bytes[4] = 0x80;
2127 assert!(matches!(
2128 Message::from_bytes(&bytes),
2129 Err(StunParseError::NotStun)
2130 ));
2131 }
2132
2133 #[test]
2134 fn parse_attribute_after_integrity() {
2135 let _log = crate::tests::test_init_log();
2136 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2137 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2138 let mut msg = Message::builder_request(BINDING);
2139 msg.add_message_integrity(&credentials, algorithm).unwrap();
2140 let mut bytes = msg.build();
2141 let software = Software::new("s").unwrap();
2142 let software_bytes = RawAttribute::from(&software).to_bytes();
2143 let software_len = software_bytes.len();
2144 bytes.extend(software_bytes);
2145 bytes[3] += software_len as u8;
2146 assert!(matches!(
2147 Message::from_bytes(&bytes),
2148 Err(StunParseError::AttributeAfterIntegrity(Software::TYPE))
2149 ));
2150 }
2151 }
2152
2153 #[test]
2154 fn parse_duplicate_integrity_after_integrity() {
2155 let _log = crate::tests::test_init_log();
2156 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2157 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2158 let mut msg = Message::builder_request(BINDING);
2159 msg.add_message_integrity(&credentials, algorithm).unwrap();
2160 msg.add_message_integrity_unchecked(&credentials, algorithm);
2162 let bytes = msg.build();
2163 let integrity_type = match algorithm {
2164 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2165 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2166 };
2167 let Err(StunParseError::AttributeAfterIntegrity(err_integrity_type)) =
2168 Message::from_bytes(&bytes)
2169 else {
2170 unreachable!();
2171 };
2172 assert_eq!(integrity_type, err_integrity_type);
2173 }
2174 }
2175
2176 #[test]
2177 fn parse_attribute_after_fingerprint() {
2178 let _log = crate::tests::test_init_log();
2179 let mut msg = Message::builder_request(BINDING);
2180 msg.add_fingerprint().unwrap();
2181 let mut bytes = msg.build();
2182 let software = Software::new("s").unwrap();
2183 let software_bytes = RawAttribute::from(&software).to_bytes();
2184 let software_len = software_bytes.len();
2185 bytes.extend(software_bytes);
2186 bytes[3] += software_len as u8;
2187 assert!(matches!(
2188 Message::from_bytes(&bytes),
2189 Err(StunParseError::AttributeAfterFingerprint(Software::TYPE))
2190 ));
2191 }
2192
2193 #[test]
2194 fn parse_duplicate_fingerprint_after_fingerprint() {
2195 let _log = crate::tests::test_init_log();
2196 let mut msg = Message::builder_request(BINDING);
2197 msg.add_fingerprint().unwrap();
2198 msg.add_fingerprint_unchecked();
2199 let bytes = msg.build();
2200 assert!(matches!(
2201 Message::from_bytes(&bytes),
2202 Err(StunParseError::AttributeAfterFingerprint(Fingerprint::TYPE))
2203 ));
2204 }
2205
2206 #[test]
2207 fn add_attribute_after_fingerprint() {
2208 let _log = crate::tests::test_init_log();
2209 let mut msg = Message::builder_request(BINDING);
2210 msg.add_fingerprint().unwrap();
2211 let software = Software::new("s").unwrap();
2212 assert!(matches!(
2213 msg.add_attribute(&software),
2214 Err(StunWriteError::FingerprintExists)
2215 ));
2216 }
2217
2218 #[test]
2219 fn add_raw_attribute_after_fingerprint() {
2220 let _log = crate::tests::test_init_log();
2221 let mut msg = Message::builder_request(BINDING);
2222 msg.add_fingerprint().unwrap();
2223 let software = Software::new("s").unwrap();
2224 let raw = software.to_raw();
2225 assert!(matches!(
2226 msg.add_raw_attribute(raw),
2227 Err(StunWriteError::FingerprintExists)
2228 ));
2229 }
2230
2231 #[test]
2232 fn parse_truncated_message_header() {
2233 let _log = crate::tests::test_init_log();
2234 let mut msg = Message::builder_request(BINDING);
2235 msg.add_fingerprint().unwrap();
2236 let bytes = msg.build();
2237 assert!(matches!(
2238 Message::from_bytes(&bytes[..8]),
2239 Err(StunParseError::Truncated {
2240 expected: 20,
2241 actual: 8
2242 })
2243 ));
2244 }
2245
2246 #[test]
2247 fn parse_truncated_message() {
2248 let _log = crate::tests::test_init_log();
2249 let mut msg = Message::builder_request(BINDING);
2250 msg.add_fingerprint().unwrap();
2251 let bytes = msg.build();
2252 assert!(matches!(
2253 Message::from_bytes(&bytes[..24]),
2254 Err(StunParseError::Truncated {
2255 expected: 28,
2256 actual: 24
2257 })
2258 ));
2259 }
2260
2261 #[test]
2262 fn parse_truncated_message_attribute() {
2263 let _log = crate::tests::test_init_log();
2264 let mut msg = Message::builder_request(BINDING);
2265 msg.add_fingerprint().unwrap();
2266 let mut bytes = msg.build();
2267 bytes[3] = 4;
2269 assert!(matches!(
2270 Message::from_bytes(&bytes[..24]),
2271 Err(StunParseError::Truncated {
2272 expected: 28,
2273 actual: 24
2274 })
2275 ));
2276 }
2277
2278 #[test]
2279 fn valid_attributes() {
2280 let _log = crate::tests::test_init_log();
2281 let mut src = Message::builder_request(BINDING);
2282 let username = Username::new("123").unwrap();
2283 src.add_attribute(&username).unwrap();
2284 let priority = Priority::new(123);
2285 src.add_attribute(&priority).unwrap();
2286 let src = src.build();
2287 let src = Message::from_bytes(&src).unwrap();
2288
2289 let res = Message::check_attribute_types(
2291 &src,
2292 &[Username::TYPE, Priority::TYPE],
2293 &[Username::TYPE],
2294 );
2295 assert!(res.is_none());
2296
2297 let res = Message::check_attribute_types(
2299 &src,
2300 &[Username::TYPE, Priority::TYPE],
2301 &[Fingerprint::TYPE],
2302 );
2303 assert!(res.is_some());
2304 let res = res.unwrap();
2305 let res = res.build();
2306 let res = Message::from_bytes(&res).unwrap();
2307 assert!(res.has_class(MessageClass::Error));
2308 assert!(res.has_method(src.method()));
2309 let err = res.attribute::<ErrorCode>().unwrap();
2310 assert_eq!(err.code(), 400);
2311
2312 let res = Message::check_attribute_types(&src, &[Username::TYPE], &[]);
2314 assert!(res.is_some());
2315 let res = res.unwrap();
2316 let data = res.build();
2317 let res = Message::from_bytes(&data).unwrap();
2318 assert!(res.has_class(MessageClass::Error));
2319 assert!(res.has_method(src.method()));
2320 let err = res.attribute::<ErrorCode>().unwrap();
2321 assert_eq!(err.code(), 420);
2322 let unknown = res.attribute::<UnknownAttributes>().unwrap();
2323 assert!(unknown.has_attribute(Priority::TYPE));
2324 }
2325
2326 #[test]
2327 #[should_panic(expected = "created from a non-request message")]
2328 fn builder_success_panic() {
2329 let _log = crate::tests::test_init_log();
2330 let msg = Message::builder(
2331 MessageType::from_class_method(MessageClass::Indication, BINDING),
2332 TransactionId::generate(),
2333 )
2334 .build();
2335 let msg = Message::from_bytes(&msg).unwrap();
2336 let _builder = Message::builder_success(&msg);
2337 }
2338
2339 #[test]
2340 #[should_panic(expected = "created from a non-request message")]
2341 fn builder_error_panic() {
2342 let _log = crate::tests::test_init_log();
2343 let msg = Message::builder(
2344 MessageType::from_class_method(MessageClass::Indication, BINDING),
2345 TransactionId::generate(),
2346 )
2347 .build();
2348 let msg = Message::from_bytes(&msg).unwrap();
2349 let _builder = Message::builder_error(&msg);
2350 }
2351
2352 #[test]
2353 #[should_panic(expected = "Use add_message_integrity() instead")]
2354 fn builder_add_attribute_integrity_panic() {
2355 let _log = crate::tests::test_init_log();
2356 let mut msg = Message::builder_request(BINDING);
2357 let hmac = [2; 20];
2358 let integrity = MessageIntegrity::new(hmac);
2359 msg.add_attribute(&integrity).unwrap();
2360 }
2361
2362 #[test]
2363 #[should_panic(expected = "Use add_message_integrity() instead")]
2364 fn builder_add_raw_attribute_integrity_panic() {
2365 let _log = crate::tests::test_init_log();
2366 let mut msg = Message::builder_request(BINDING);
2367 let hmac = [2; 20];
2368 let integrity = MessageIntegrity::new(hmac);
2369 let raw = integrity.to_raw();
2370 msg.add_raw_attribute(raw).unwrap();
2371 }
2372
2373 #[test]
2374 #[should_panic(expected = "Use add_message_integrity() instead")]
2375 fn builder_add_attribute_integrity_sha256_panic() {
2376 let _log = crate::tests::test_init_log();
2377 let mut msg = Message::builder_request(BINDING);
2378 let hmac = [2; 16];
2379 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
2380 msg.add_attribute(&integrity).unwrap();
2381 }
2382
2383 #[test]
2384 #[should_panic(expected = "Use add_message_integrity() instead")]
2385 fn builder_add_raw_attribute_integrity_sha256_panic() {
2386 let _log = crate::tests::test_init_log();
2387 let mut msg = Message::builder_request(BINDING);
2388 let hmac = [2; 16];
2389 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
2390 let raw = integrity.to_raw();
2391 msg.add_raw_attribute(raw).unwrap();
2392 }
2393
2394 #[test]
2395 #[should_panic(expected = "Use add_fingerprint() instead")]
2396 fn builder_add_attribute_fingerprint_panic() {
2397 let _log = crate::tests::test_init_log();
2398 let mut msg = Message::builder_request(BINDING);
2399 let fingerprint = [2; 4];
2400 let fingerprint = Fingerprint::new(fingerprint);
2401 msg.add_attribute(&fingerprint).unwrap();
2402 }
2403
2404 #[test]
2405 #[should_panic(expected = "Use add_fingerprint() instead")]
2406 fn builder_add_raw_attribute_fingerprint_panic() {
2407 let _log = crate::tests::test_init_log();
2408 let mut msg = Message::builder_request(BINDING);
2409 let fingerprint = [2; 4];
2410 let fingerprint = Fingerprint::new(fingerprint);
2411 let raw = fingerprint.to_raw();
2412 msg.add_raw_attribute(raw).unwrap();
2413 }
2414
2415 #[test]
2416 fn rfc5769_vector1() {
2417 let _log = crate::tests::test_init_log();
2418 let data = vec![
2420 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, ];
2448 let msg = Message::from_bytes(&data).unwrap();
2449 assert!(msg.has_class(MessageClass::Request));
2450 assert!(msg.has_method(BINDING));
2451 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
2452
2453 let mut builder = Message::builder(
2454 MessageType::from_class_method(MessageClass::Request, BINDING),
2455 msg.transaction_id(),
2456 );
2457
2458 assert!(msg.has_attribute(Software::TYPE));
2460 let raw = msg.raw_attribute(Software::TYPE).unwrap();
2461 assert!(matches!(Software::try_from(&raw), Ok(_)));
2462 let software = Software::try_from(&raw).unwrap();
2463 assert_eq!(software.software(), "STUN test client");
2464 builder.add_attribute(&software).unwrap();
2465
2466 assert!(msg.has_attribute(Priority::TYPE));
2468 let raw = msg.raw_attribute(Priority::TYPE).unwrap();
2469 assert!(matches!(Priority::try_from(&raw), Ok(_)));
2470 let priority = Priority::try_from(&raw).unwrap();
2471 assert_eq!(priority.priority(), 0x6e0001ff);
2472 builder.add_attribute(&priority).unwrap();
2473
2474 assert!(msg.has_attribute(IceControlled::TYPE));
2476 let raw = msg.raw_attribute(IceControlled::TYPE).unwrap();
2477 assert!(matches!(IceControlled::try_from(&raw), Ok(_)));
2478 let ice = IceControlled::try_from(&raw).unwrap();
2479 assert_eq!(ice.tie_breaker(), 0x932f_f9b1_5126_3b36);
2480 builder.add_attribute(&ice).unwrap();
2481
2482 assert!(msg.has_attribute(Username::TYPE));
2484 let raw = msg.raw_attribute(Username::TYPE).unwrap();
2485 assert!(matches!(Username::try_from(&raw), Ok(_)));
2486 let username = Username::try_from(&raw).unwrap();
2487 assert_eq!(username.username(), "evtj:h6vY");
2488 builder.add_attribute(&username).unwrap();
2489
2490 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
2492 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
2493 });
2494 assert!(matches!(
2495 msg.validate_integrity(&credentials),
2496 Ok(IntegrityAlgorithm::Sha1)
2497 ));
2498 builder
2499 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2500 .unwrap();
2501
2502 assert!(msg.has_attribute(Fingerprint::TYPE));
2504 builder.add_fingerprint().unwrap();
2505
2506 let mut msg_data = builder.build();
2508 msg_data[73] = 0x20;
2510 msg_data[74] = 0x20;
2511 msg_data[75] = 0x20;
2512 assert_eq!(msg_data[..80], data[..80]);
2515 }
2516
2517 #[test]
2518 fn rfc5769_vector2() {
2519 let _log = crate::tests::test_init_log();
2520 let data = vec![
2522 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, ];
2543
2544 let msg = Message::from_bytes(&data).unwrap();
2545 assert!(msg.has_class(MessageClass::Success));
2546 assert!(msg.has_method(BINDING));
2547 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
2548 let mut builder = Message::builder(
2549 MessageType::from_class_method(MessageClass::Success, BINDING),
2550 msg.transaction_id(),
2551 );
2552
2553 assert!(msg.has_attribute(Software::TYPE));
2555 let raw = msg.raw_attribute(Software::TYPE).unwrap();
2556 assert!(matches!(Software::try_from(&raw), Ok(_)));
2557 let software = Software::try_from(&raw).unwrap();
2558 assert_eq!(software.software(), "test vector");
2559 builder.add_attribute(&software).unwrap();
2560
2561 assert!(msg.has_attribute(XorMappedAddress::TYPE));
2563 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
2564 assert!(matches!(XorMappedAddress::try_from(&raw), Ok(_)));
2565 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
2566 assert_eq!(
2567 xor_mapped_addres.addr(msg.transaction_id()),
2568 "192.0.2.1:32853".parse().unwrap()
2569 );
2570 builder.add_attribute(&xor_mapped_addres).unwrap();
2571
2572 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
2574 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
2575 });
2576 let ret = msg.validate_integrity(&credentials);
2577 debug!("{:?}", ret);
2578 assert!(matches!(ret, Ok(IntegrityAlgorithm::Sha1)));
2579 builder
2580 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2581 .unwrap();
2582
2583 assert!(msg.has_attribute(Fingerprint::TYPE));
2585 builder.add_fingerprint().unwrap();
2586
2587 let mut msg_data = builder.build();
2589 msg_data[35] = 0x20;
2591 assert_eq!(msg_data[..52], data[..52]);
2592 }
2593
2594 #[test]
2595 fn rfc5769_vector3() {
2596 let _log = crate::tests::test_init_log();
2597 let data = vec![
2599 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, ];
2623
2624 let msg = Message::from_bytes(&data).unwrap();
2625 assert!(msg.has_class(MessageClass::Success));
2626 assert!(msg.has_method(BINDING));
2627 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
2628 let mut builder = Message::builder(
2629 MessageType::from_class_method(MessageClass::Success, BINDING),
2630 msg.transaction_id(),
2631 );
2632
2633 assert!(msg.has_attribute(Software::TYPE));
2635 let raw = msg.raw_attribute(Software::TYPE).unwrap();
2636 assert!(matches!(Software::try_from(&raw), Ok(_)));
2637 let software = Software::try_from(&raw).unwrap();
2638 assert_eq!(software.software(), "test vector");
2639 builder.add_attribute(&software).unwrap();
2640
2641 assert!(msg.has_attribute(XorMappedAddress::TYPE));
2643 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
2644 assert!(matches!(XorMappedAddress::try_from(&raw), Ok(_)));
2645 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
2646 assert_eq!(
2647 xor_mapped_addres.addr(msg.transaction_id()),
2648 "[2001:db8:1234:5678:11:2233:4455:6677]:32853"
2649 .parse()
2650 .unwrap()
2651 );
2652 builder.add_attribute(&xor_mapped_addres).unwrap();
2653
2654 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
2656 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
2657 });
2658 assert!(matches!(
2659 msg.validate_integrity(&credentials),
2660 Ok(IntegrityAlgorithm::Sha1)
2661 ));
2662 builder
2663 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2664 .unwrap();
2665
2666 assert!(msg.has_attribute(Fingerprint::TYPE));
2668 builder.add_fingerprint().unwrap();
2669
2670 let mut msg_data = builder.build();
2672 msg_data[35] = 0x20;
2674 assert_eq!(msg_data[..64], data[..64]);
2675 }
2676
2677 #[test]
2678 fn rfc5769_vector4() {
2679 let _log = crate::tests::test_init_log();
2680 let data = vec![
2682 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, ];
2712
2713 let msg = Message::from_bytes(&data).unwrap();
2714 assert!(msg.has_class(MessageClass::Request));
2715 assert!(msg.has_method(BINDING));
2716 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
2717 let mut builder = Message::builder(
2718 MessageType::from_class_method(MessageClass::Request, BINDING),
2719 msg.transaction_id(),
2720 );
2721
2722 let long_term = LongTermCredentials {
2723 username: "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}".to_owned(),
2724 password: "The\u{00AD}M\u{00AA}tr\u{2168}".to_owned(),
2725 realm: "example.org".to_owned(),
2726 };
2727 assert!(msg.has_attribute(Username::TYPE));
2729 let raw = msg.raw_attribute(Username::TYPE).unwrap();
2730 assert!(matches!(Username::try_from(&raw), Ok(_)));
2731 let username = Username::try_from(&raw).unwrap();
2732 assert_eq!(username.username(), &long_term.username);
2733 builder.add_attribute(&username).unwrap();
2734
2735 let expected_nonce = "f//499k954d6OL34oL9FSTvy64sA";
2737 assert!(msg.has_attribute(Nonce::TYPE));
2738 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
2739 assert!(matches!(Nonce::try_from(&raw), Ok(_)));
2740 let nonce = Nonce::try_from(&raw).unwrap();
2741 assert_eq!(nonce.nonce(), expected_nonce);
2742 builder.add_attribute(&nonce).unwrap();
2743
2744 assert!(msg.has_attribute(Realm::TYPE));
2746 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
2747 assert!(matches!(Realm::try_from(&raw), Ok(_)));
2748 let realm = Realm::try_from(&raw).unwrap();
2749 assert_eq!(realm.realm(), long_term.realm());
2750 builder.add_attribute(&realm).unwrap();
2751
2752 assert_eq!(builder.build()[4..], data[4..92]);
2760 }
2761
2762 #[test]
2763 fn rfc8489_vector1() {
2764 let _log = crate::tests::test_init_log();
2765 let data = vec![
2768 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, ];
2810
2811 let msg = Message::from_bytes(&data).unwrap();
2812 assert!(msg.has_class(MessageClass::Request));
2813 assert!(msg.has_method(BINDING));
2814 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
2815 let mut builder = Message::builder(
2816 MessageType::from_class_method(MessageClass::Success, BINDING),
2817 msg.transaction_id(),
2818 );
2819
2820 let long_term = LongTermCredentials {
2821 username: "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}".to_owned(),
2822 password: "The\u{00AD}M\u{00AA}tr\u{2168}".to_owned(),
2823 realm: "example.org".to_owned(),
2824 };
2825 assert!(msg.has_attribute(Userhash::TYPE));
2827 let raw = msg.raw_attribute(Userhash::TYPE).unwrap();
2828 assert!(matches!(Userhash::try_from(&raw), Ok(_)));
2829 let userhash = Userhash::try_from(&raw).unwrap();
2830 builder.add_attribute(&userhash).unwrap();
2831
2832 let expected_nonce = "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA";
2834 assert!(msg.has_attribute(Nonce::TYPE));
2835 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
2836 assert!(matches!(Nonce::try_from(&raw), Ok(_)));
2837 let nonce = Nonce::try_from(&raw).unwrap();
2838 assert_eq!(nonce.nonce(), expected_nonce);
2839 builder.add_attribute(&nonce).unwrap();
2840
2841 assert!(msg.has_attribute(Realm::TYPE));
2843 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
2844 assert!(matches!(Realm::try_from(&raw), Ok(_)));
2845 let realm = Realm::try_from(&raw).unwrap();
2846 assert_eq!(realm.realm(), long_term.realm);
2847 builder.add_attribute(&realm).unwrap();
2848
2849 assert!(msg.has_attribute(PasswordAlgorithm::TYPE));
2851 let raw = msg.raw_attribute(PasswordAlgorithm::TYPE).unwrap();
2852 assert!(matches!(PasswordAlgorithm::try_from(&raw), Ok(_)));
2853 let algo = PasswordAlgorithm::try_from(&raw).unwrap();
2854 assert_eq!(algo.algorithm(), PasswordAlgorithmValue::SHA256);
2855 builder.add_attribute(&algo).unwrap();
2856
2857 assert_eq!(builder.build()[4..], data[4..128]);
2865 }
2866}